Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/taviso/loadlibrary.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTavis Ormandy <taviso@gmail.com>2020-03-02 08:06:28 +0300
committerTavis Ormandy <taviso@gmail.com>2020-03-02 08:06:28 +0300
commit3b76c18a146b880087491f15b0038ef838c9a928 (patch)
tree06e6c649a7fd6421ec8fa172edbb63069fd2344e
parenta4379b27b4bbcc5069b467c2928e94433661de17 (diff)
testing support for more engines
-rw-r--r--.gdbinit85
-rw-r--r--.gitignore3
-rw-r--r--Makefile13
-rw-r--r--peloader/pe_linker.c33
-rw-r--r--peloader/pe_linker.h79
-rw-r--r--peloader/winapi/Heap.c29
-rw-r--r--peloader/winapi/Internal.c77
-rw-r--r--peloader/winapi/rtlbitmap.c1129
-rw-r--r--peloader/winnt_types.h24
9 files changed, 1458 insertions, 14 deletions
diff --git a/.gdbinit b/.gdbinit
new file mode 100644
index 0000000..7c4ea45
--- /dev/null
+++ b/.gdbinit
@@ -0,0 +1,85 @@
+define multichar
+ printf "'%c%c%c%c'\n", (((uint32_t) $arg0 >> 24) & 0xff) \
+ , (((uint32_t) $arg0 >> 16) & 0xff) \
+ , (((uint32_t) $arg0 >> 8) & 0xff) \
+ , (((uint32_t) $arg0 >> 0) & 0xff)
+end
+document multichar
+Decode and display a multichar constant value.
+end
+
+alias mc = multichar
+
+# The nexti instruction can be unrealiable when debugging Windows code, this is
+# a hacky function to use hardware breakpoints instead.
+define hnexti
+ # Record the number of the last breapoint.
+ set $_bpnum = $bpnum
+
+ # Make sure its always defined.
+ init-if-undefined $_bpnum = -1
+
+ # Try to guess the location of the next instruction.
+ if (*(uint8_t *) $pc == 0xe8)
+ thb *($pc + 5)
+ end
+
+ if (*(uint8_t *) $pc == 0xff)
+ set $_modrm = *(uint8_t *)($pc + 1)
+ set $_mod = ($_modrm & 0b11000000) >> 6
+ set $_reg = ($_modrm & 0b00111000) >> 3
+ set $_rm = ($_modrm & 0b00000111) >> 0
+
+ # See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte"
+ printf "MODRM %#X => MOD %#X R/M %#X REG %#X\n",$_modrm,$_mod,$_reg,$_rm
+
+ # These are all 1 byte operand except 0b101 and 0b100
+ if ($_mod == 0b00)
+ # disp32
+ if ($_rm == 0b101)
+ thb *($pc + 6)
+ end
+ # [--][--] Add one for SIB
+ if ($_rm == 0b100)
+ thb *($pc + 3)
+ end
+ # [r32]
+ if ($bpnum == $_bpnum)
+ thb *($pc + 2)
+ end
+ end
+ # 0b11 is register direct, i.e. call r32
+ if ($_mod == 0b11)
+ thb *($pc + 2)
+ end
+ end
+
+ if ($bpnum != $_bpnum)
+ continue
+ else
+ print "Failed to set breakpoint, or unknown instruction"
+ end
+end
+document hnexti
+Like nexti, but use hardware breakpoints.
+end
+
+alias hni = hnexti
+
+define ni
+ print "Are you sure? nexti is unreliable when debugging Windows code..."
+end
+
+define trace
+ while 1
+ eval "set $_cond=!!(%s)",$arg0
+ if ! $_cond
+ loop_break
+ end
+ si
+ end
+end
+document trace
+Step until condition is true.
+Ex: trace "$eax != 4"
+end
diff --git a/.gitignore b/.gitignore
index c114d20..fcf6377 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,5 @@
*.vdm
*.exe
mpclient
-mpscript
+avscript
+eicar.com
diff --git a/Makefile b/Makefile
index 7d6f0dd..2adc55a 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ LDLIBS = intercept/libdisasm.a -Wl,--whole-archive,peloader/libpeloader.a,--no-
.PHONY: clean peloader intercept
-TARGETS=mpclient
+TARGETS=mpclient | peloader
all: $(TARGETS)
-mkdir -p faketemp
@@ -16,22 +16,17 @@ intercept:
peloader:
make -C peloader all
-script.h: javascript.txt
- hexdump -v -e '8/1 "%#02x," "\n"' < $^ > $@
-
-mpscript.o: script.h
-
intercept/hook.o: intercept
mpclient: mpclient.o intercept/hook.o | peloader
$(CC) $(CFLAGS) $^ -o $@ $(LDLIBS) $(LDFLAGS)
-# mpscript requires libreadline-dev:i386
-mpscript: mpscript.o intercept/hook.o | peloader
+# avscript requires libreadline-dev:i386
+avscript: avscript.o intercept/hook.o | peloader
$(CC) $(CFLAGS) $^ -o $@ $(LDLIBS) $(LDFLAGS) -lreadline
clean:
- rm -f a.out core *.o core.* vgcore.* gmon.out script.h mpclient mpscript
+ rm -f a.out core *.o core.* vgcore.* gmon.out script.h mpclient avscript
make -C intercept clean
make -C peloader clean
rm -rf faketemp
diff --git a/peloader/pe_linker.c b/peloader/pe_linker.c
index f0e4737..aaca663 100644
--- a/peloader/pe_linker.c
+++ b/peloader/pe_linker.c
@@ -27,6 +27,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
+#include <limits.h>
#include <errno.h>
#include <string.h>
#include <search.h>
@@ -48,6 +49,7 @@ struct pe_exports {
static struct pe_exports *pe_exports;
static int num_pe_exports;
+PKUSER_SHARED_DATA SharedUserData;
#define DRIVER_NAME "pelinker"
#define RVA2VA(image, rva, type) (type)(ULONG_PTR)((void *)image + rva)
@@ -91,6 +93,12 @@ extern struct wrap_export crt_exports[];
uintptr_t LocalStorage[1024] = {0};
+static ULONG TlsBitmapData[32];
+static RTL_BITMAP TlsBitmap = {
+ .SizeOfBitMap = sizeof(TlsBitmapData) * CHAR_BIT,
+ .Buffer = (PVOID) &TlsBitmapData[0],
+};
+
struct hsearch_data extraexports;
struct hsearch_data crtexports;
@@ -639,6 +647,9 @@ bool pe_load_library(const char *filename, void **image, size_t *size)
// code that uses SEH as it accesses it via fs selector.
setup_nt_threadinfo(NULL);
+ // Install a minimal KUSER_SHARED_DATA structure.
+ setup_kuser_shared_data();
+
return true;
error:
@@ -654,9 +665,13 @@ error:
bool setup_nt_threadinfo(PEXCEPTION_HANDLER ExceptionHandler)
{
static EXCEPTION_FRAME ExceptionFrame;
+ static PEB ProcessEnvironmentBlock = {
+ .TlsBitmap = &TlsBitmap,
+ };
static TEB ThreadEnvironment = {
.Tib.Self = &ThreadEnvironment.Tib,
.ThreadLocalStoragePointer = LocalStorage, // https://github.com/taviso/loadlibrary/issues/65
+ .ProcessEnvironmentBlock = &ProcessEnvironmentBlock,
};
struct user_desc pebdescriptor = {
.entry_number = -1,
@@ -688,3 +703,21 @@ bool setup_nt_threadinfo(PEXCEPTION_HANDLER ExceptionHandler)
return true;
}
+
+// Minimal KUSER_SHARED_DATA structure, for those applications that require it.
+bool setup_kuser_shared_data(void)
+{
+ SharedUserData = mmap((PVOID)(MM_SHARED_USER_DATA_VA),
+ sizeof(KUSER_SHARED_DATA),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+ -1,
+ 0);
+
+ if (SharedUserData == MAP_FAILED) {
+ DebugLog("failed to map KUSER_SHARED_DATA, %m");
+ return false;
+ }
+
+ return true;
+}
diff --git a/peloader/pe_linker.h b/peloader/pe_linker.h
index 4837bf7..166d154 100644
--- a/peloader/pe_linker.h
+++ b/peloader/pe_linker.h
@@ -986,12 +986,87 @@ typedef struct _CLIENT_ID {
HANDLE UniqueThread;
} CLIENT_ID;
+typedef struct _LIST_ENTRY {
+ struct _LIST_ENTRY *Flink;
+ struct _LIST_ENTRY *Blink;
+} LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY;
+
+typedef struct _PEB_LDR_DATA
+{
+ ULONG Length;
+ BOOLEAN Initialized;
+ PVOID SsHandle;
+ LIST_ENTRY InLoadOrderModuleList;
+ LIST_ENTRY InMemoryOrderModuleList;
+ LIST_ENTRY InInitializationOrderModuleList;
+} PEB_LDR_DATA, *PPEB_LDR_DATA;
+
+typedef struct _PEB
+{
+ BOOLEAN InheritedAddressSpace; /* 0x00 */
+ BOOLEAN ReadImageFileExecOptions; /* 0x01 */
+ BOOLEAN BeingDebugged; /* 0x02 */
+ BOOLEAN SpareBool; /* 0x03 */
+ HANDLE Mutant; /* 0x04 */
+ HMODULE ImageBaseAddress; /* 0x08 */
+ PPEB_LDR_DATA LdrData; /* 0x0c */
+ PVOID ProcessParameters; /* 0x10 */
+ PVOID SubSystemData; /* 0x14 */
+ HANDLE ProcessHeap; /* 0x18 */
+ PVOID FastPebLock; /* 0x1c */
+ PVOID FastPebLockRoutine; /* 0x20 */
+ PVOID FastPebUnlockRoutine; /* 0x24 */
+ ULONG EnvironmentUpdateCount; /* 0x28 */
+ PVOID KernelCallbackTable; /* 0x2c */
+ PVOID EventLogSection; /* 0x30 */
+ PVOID EventLog; /* 0x34 */
+ PVOID FreeList; /* 0x38 */
+ ULONG TlsExpansionCounter; /* 0x3c */
+ PRTL_BITMAP TlsBitmap; /* 0x40 */
+ ULONG TlsBitmapBits[2]; /* 0x44 */
+ PVOID ReadOnlySharedMemoryBase; /* 0x4c */
+ PVOID ReadOnlySharedMemoryHeap; /* 0x50 */
+ PVOID *ReadOnlyStaticServerData; /* 0x54 */
+ PVOID AnsiCodePageData; /* 0x58 */
+ PVOID OemCodePageData; /* 0x5c */
+ PVOID UnicodeCaseTableData; /* 0x60 */
+ ULONG NumberOfProcessors; /* 0x64 */
+ ULONG NtGlobalFlag; /* 0x68 */
+ BYTE Spare2[4]; /* 0x6c */
+ LARGE_INTEGER CriticalSectionTimeout; /* 0x70 */
+ ULONG HeapSegmentReserve; /* 0x78 */
+ ULONG HeapSegmentCommit; /* 0x7c */
+ ULONG HeapDeCommitTotalFreeThreshold; /* 0x80 */
+ ULONG HeapDeCommitFreeBlockThreshold; /* 0x84 */
+ ULONG NumberOfHeaps; /* 0x88 */
+ ULONG MaximumNumberOfHeaps; /* 0x8c */
+ PVOID *ProcessHeaps; /* 0x90 */
+ PVOID GdiSharedHandleTable; /* 0x94 */
+ PVOID ProcessStarterHelper; /* 0x98 */
+ PVOID GdiDCAttributeList; /* 0x9c */
+ PVOID LoaderLock; /* 0xa0 */
+ ULONG OSMajorVersion; /* 0xa4 */
+ ULONG OSMinorVersion; /* 0xa8 */
+ ULONG OSBuildNumber; /* 0xac */
+ ULONG OSPlatformId; /* 0xb0 */
+ ULONG ImageSubSystem; /* 0xb4 */
+ ULONG ImageSubSystemMajorVersion; /* 0xb8 */
+ ULONG ImageSubSystemMinorVersion; /* 0xbc */
+ ULONG ImageProcessAffinityMask; /* 0xc0 */
+ ULONG GdiHandleBuffer[34]; /* 0xc4 */
+ ULONG PostProcessInitRoutine; /* 0x14c */
+ PRTL_BITMAP TlsExpansionBitmap; /* 0x150 */
+ ULONG TlsExpansionBitmapBits[32]; /* 0x154 */
+ ULONG SessionId; /* 0x1d4 */
+} PEB, *PPEB;
+
typedef struct _TEB {
NT_TIB Tib;
PVOID EnvironmentPointer;
CLIENT_ID Cid;
PVOID ActiveRpcInfo;
PVOID ThreadLocalStoragePointer;
+ PPEB ProcessEnvironmentBlock;
// The fields below this are deliberately omitted so that access causes a
// crash (because of the segment limit). This lets me know I have to fix
// it, otherwise the error is very difficult to track down.
@@ -1027,5 +1102,9 @@ int link_pe_images(struct pe_image *pe_image, unsigned short n);
int get_export(const char *name, void *func);
int get_data_export(char *name, uint32_t base, void *result);
bool setup_nt_threadinfo(PEXCEPTION_HANDLER handler);
+bool setup_kuser_shared_data(void);
bool process_extra_exports(void *imagebase, size_t base, const char *filename);
+
+extern PKUSER_SHARED_DATA SharedUserData;
+
#endif
diff --git a/peloader/winapi/Heap.c b/peloader/winapi/Heap.c
index 3645ee8..21d1de9 100644
--- a/peloader/winapi/Heap.c
+++ b/peloader/winapi/Heap.c
@@ -78,6 +78,33 @@ STATIC PVOID WINAPI LocalFree(PVOID hMem)
return NULL;
}
+STATIC PVOID WINAPI RtlCreateHeap(ULONG Flags,
+ PVOID HeapBase,
+ SIZE_T ReserveSize,
+ SIZE_T CommitSize,
+ PVOID Lock,
+ PVOID Parameters)
+{
+ DebugLog("%#x, %p, %#x, %#x, %p, %p",
+ Flags,
+ HeapBase,
+ ReserveSize,
+ CommitSize,
+ Lock,
+ Parameters);
+
+ return (HANDLE) 'HEAP';
+}
+
+STATIC PVOID WINAPI RtlAllocateHeap(PVOID HeapHandle,
+ ULONG Flags,
+ SIZE_T Size)
+{
+ DebugLog("%p, %#x, %u", HeapHandle, Flags, Size);
+
+ return malloc(Size);
+}
+
DECLARE_CRT_EXPORT("HeapCreate", HeapCreate);
DECLARE_CRT_EXPORT("GetProcessHeap", GetProcessHeap);
DECLARE_CRT_EXPORT("HeapAlloc", HeapAlloc);
@@ -86,3 +113,5 @@ DECLARE_CRT_EXPORT("HeapSize", HeapSize);
DECLARE_CRT_EXPORT("HeapReAlloc", HeapReAlloc);
DECLARE_CRT_EXPORT("LocalAlloc", LocalAlloc);
DECLARE_CRT_EXPORT("LocalFree", LocalFree);
+DECLARE_CRT_EXPORT("RtlCreateHeap", RtlCreateHeap);
+DECLARE_CRT_EXPORT("RtlAllocateHeap", RtlAllocateHeap);
diff --git a/peloader/winapi/Internal.c b/peloader/winapi/Internal.c
new file mode 100644
index 0000000..d4de69f
--- /dev/null
+++ b/peloader/winapi/Internal.c
@@ -0,0 +1,77 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdbool.h>
+#include <search.h>
+
+#include "winnt_types.h"
+#include "pe_linker.h"
+#include "ntoskernel.h"
+#include "log.h"
+#include "winexports.h"
+#include "util.h"
+
+void WINAPI RtlAcquirePebLock(void)
+{
+ DebugLog("");
+ return;
+}
+
+void WINAPI RtlReleasePebLock(void)
+{
+ DebugLog("");
+ return;
+}
+
+NTSTATUS WINAPI LdrGetDllHandle(PWCHAR pwPath, PVOID unused, PUNICODE_STRING ModuleFileName, PHANDLE pHModule)
+{
+ DebugLog("%S %p %p %p", pwPath, unused, ModuleFileName, pHModule);
+ pHModule = (HANDLE) 'LDRP';
+ return 0;
+}
+
+NTSTATUS WINAPI EtwRegister(PVOID ProvideId, PVOID EnableCallback, PVOID CallbackContext, PVOID RegHandle)
+{
+ DebugLog("");
+ return 0;
+}
+
+NTSTATUS WINAPI EtwUnregister(HANDLE RegHandle)
+{
+ DebugLog("");
+ return 0;
+}
+
+ULONG WINAPI EtwEventWrite(HANDLE RegHAndle, PVOID EventDescriptor, ULONG UserDataCount, PVOID UserData, PVOID a5)
+{
+ DebugLog("");
+ return 0;
+}
+
+NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE Module,
+ PANSI_STRING Name,
+ WORD Ordinal,
+ PVOID *Address)
+{
+ DebugLog("%p %s %hu %p", Module, Name->buf, Ordinal, Address);
+
+ // Recognizable value to crash on.
+ *Address = (PVOID) 'LDRZ';
+
+ if (strcmp(Name->buf, "EtwEventRegister") == 0) {
+ *Address = EtwRegister;
+ }
+ if (strcmp(Name->buf, "EtwEventUnregister") == 0) {
+ *Address = EtwUnregister;
+ }
+ if (strcmp(Name->buf, "EtwEventWrite") == 0) {
+ *Address = EtwEventWrite;
+ }
+
+ return 0;
+}
+
+DECLARE_CRT_EXPORT("RtlAcquirePebLock", RtlAcquirePebLock);
+DECLARE_CRT_EXPORT("RtlReleasePebLock", RtlReleasePebLock);
+DECLARE_CRT_EXPORT("LdrGetDllHandle", LdrGetDllHandle);
+DECLARE_CRT_EXPORT("LdrGetProcedureAddress", LdrGetProcedureAddress);
diff --git a/peloader/winapi/rtlbitmap.c b/peloader/winapi/rtlbitmap.c
new file mode 100644
index 0000000..9503c8e
--- /dev/null
+++ b/peloader/winapi/rtlbitmap.c
@@ -0,0 +1,1129 @@
+/*
+ * NTDLL bitmap functions
+ *
+ * Copyright 2002 Jon Griffiths
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * NOTES
+ * Bitmaps are an efficient type for manipulating large arrays of bits. They
+ * are commonly used by device drivers (e.g. For holding dirty/free blocks),
+ * but are also available to applications that need this functionality.
+ *
+ * Bits are set LSB to MSB in each consecutive byte, making this implementation
+ * binary compatible with Win32.
+ *
+ * Note that to avoid unexpected behaviour, the size of a bitmap should be set
+ * to a multiple of 32.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdbool.h>
+#include <search.h>
+
+#include "winnt_types.h"
+#include "pe_linker.h"
+#include "ntoskernel.h"
+#include "log.h"
+#include "winexports.h"
+#include "util.h"
+
+#define TRACE DebugLog
+#define FIXME DebugLog
+
+/* Bits set from LSB to MSB; used as mask for runs < 8 bits */
+static const BYTE NTDLL_maskBits[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };
+
+/* Number of set bits for each value of a nibble; used for counting */
+static const BYTE NTDLL_nibbleBitCount[16] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
+};
+
+/* First set bit in a nibble; used for determining least significant bit */
+static const BYTE NTDLL_leastSignificant[16] = {
+ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Last set bit in a nibble; used for determining most significant bit */
+static const signed char NTDLL_mostSignificant[16] = {
+ -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+};
+
+/*************************************************************************
+ * RtlInitializeBitMap [NTDLL.@]
+ *
+ * Initialise a new bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * lpBuff [I] Memory for the bitmap
+ * ulSize [I] Size of lpBuff in bits
+ *
+ * RETURNS
+ * Nothing.
+ *
+ * NOTES
+ * lpBuff must be aligned on a ULONG suitable boundary, to a multiple of 32 bytes
+ * in size (irrespective of ulSize given).
+ */
+VOID WINAPI RtlInitializeBitMap(PRTL_BITMAP lpBits, PULONG lpBuff, ULONG ulSize)
+{
+ TRACE("(%p,%p,%u)\n", lpBits,lpBuff,ulSize);
+ lpBits->SizeOfBitMap = ulSize;
+ lpBits->Buffer = (PVOID) lpBuff;
+}
+
+/*************************************************************************
+ * RtlSetAllBits [NTDLL.@]
+ *
+ * Set all bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ *
+ * RETURNS
+ * Nothing.
+ */
+VOID WINAPI RtlSetAllBits(PRTL_BITMAP lpBits)
+{
+ TRACE("(%p)\n", lpBits);
+ memset(lpBits->Buffer, 0xff, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
+}
+
+/*************************************************************************
+ * RtlClearAllBits [NTDLL.@]
+ *
+ * Clear all bits in a bitmap.
+ *
+ * PARAMS
+ * lpBit [I] Bitmap pointer
+ *
+ * RETURNS
+ * Nothing.
+ */
+VOID WINAPI RtlClearAllBits(PRTL_BITMAP lpBits)
+{
+ TRACE("(%p)\n", lpBits);
+ memset(lpBits->Buffer, 0, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
+}
+
+/*************************************************************************
+ * RtlSetBits [NTDLL.@]
+ *
+ * Set a range of bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulStart [I] First bit to set
+ * ulCount [I] Number of consecutive bits to set
+ *
+ * RETURNS
+ * Nothing.
+ */
+VOID WINAPI RtlSetBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
+{
+ LPBYTE lpOut;
+
+ TRACE("(%p,%u,%u)\n", lpBits, ulStart, ulCount);
+
+ if (!lpBits || !ulCount ||
+ ulStart >= lpBits->SizeOfBitMap ||
+ ulCount > lpBits->SizeOfBitMap - ulStart)
+ return;
+
+ /* FIXME: It might be more efficient/cleaner to manipulate four bytes
+ * at a time. But beware of the pointer arithmetics...
+ */
+ lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
+
+ /* Set bits in first byte, if ulStart isn't a byte boundary */
+ if (ulStart & 7)
+ {
+ if (ulCount > 7)
+ {
+ /* Set from start bit to the end of the byte */
+ *lpOut++ |= 0xff << (ulStart & 7);
+ ulCount -= (8 - (ulStart & 7));
+ }
+ else
+ {
+ /* Set from the start bit, possibly into the next byte also */
+ USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
+
+ *lpOut |= (initialWord & 0xff);
+ if (initialWord >> 8) lpOut[1] |= (initialWord >> 8);
+ return;
+ }
+ }
+
+ /* Set bits up to complete byte count */
+ if (ulCount >> 3)
+ {
+ memset(lpOut, 0xff, ulCount >> 3);
+ lpOut = lpOut + (ulCount >> 3);
+ }
+
+ /* Set remaining bits, if any */
+ if (ulCount & 0x7)
+ *lpOut |= NTDLL_maskBits[ulCount & 0x7];
+}
+
+/*************************************************************************
+ * RtlClearBits [NTDLL.@]
+ *
+ * Clear bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulStart [I] First bit to set
+ * ulCount [I] Number of consecutive bits to clear
+ *
+ * RETURNS
+ * Nothing.
+ */
+VOID WINAPI RtlClearBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
+{
+ LPBYTE lpOut;
+
+ TRACE("(%p,%u,%u)\n", lpBits, ulStart, ulCount);
+
+ if (!lpBits || !ulCount ||
+ ulStart >= lpBits->SizeOfBitMap ||
+ ulCount > lpBits->SizeOfBitMap - ulStart)
+ return;
+
+ /* FIXME: It might be more efficient/cleaner to manipulate four bytes
+ * at a time. But beware of the pointer arithmetics...
+ */
+ lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
+
+ /* Clear bits in first byte, if ulStart isn't a byte boundary */
+ if (ulStart & 7)
+ {
+ if (ulCount > 7)
+ {
+ /* Clear from start bit to the end of the byte */
+ *lpOut++ &= ~(0xff << (ulStart & 7));
+ ulCount -= (8 - (ulStart & 7));
+ }
+ else
+ {
+ /* Clear from the start bit, possibly into the next byte also */
+ USHORT initialWord = ~(NTDLL_maskBits[ulCount] << (ulStart & 7));
+
+ *lpOut &= (initialWord & 0xff);
+ if ((initialWord >> 8) != 0xff) lpOut[1] &= (initialWord >> 8);
+ return;
+ }
+ }
+
+ /* Clear bits (in blocks of 8) on whole byte boundaries */
+ if (ulCount >> 3)
+ {
+ memset(lpOut, 0, ulCount >> 3);
+ lpOut = lpOut + (ulCount >> 3);
+ }
+
+ /* Clear remaining bits, if any */
+ if (ulCount & 0x7)
+ *lpOut &= ~NTDLL_maskBits[ulCount & 0x7];
+}
+
+/*************************************************************************
+ * RtlAreBitsSet [NTDLL.@]
+ *
+ * Determine if part of a bitmap is set.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulStart [I] First bit to check from
+ * ulCount [I] Number of consecutive bits to check
+ *
+ * RETURNS
+ * TRUE, If ulCount bits from ulStart are set.
+ * FALSE, Otherwise.
+ */
+BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
+{
+ LPBYTE lpOut;
+ ULONG ulRemainder;
+
+ TRACE("(%p,%u,%u)\n", lpBits, ulStart, ulCount);
+
+ if (!lpBits || !ulCount ||
+ ulStart >= lpBits->SizeOfBitMap ||
+ ulCount > lpBits->SizeOfBitMap - ulStart)
+ return FALSE;
+
+ /* FIXME: It might be more efficient/cleaner to manipulate four bytes
+ * at a time. But beware of the pointer arithmetics...
+ */
+ lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
+
+ /* Check bits in first byte, if ulStart isn't a byte boundary */
+ if (ulStart & 7)
+ {
+ if (ulCount > 7)
+ {
+ /* Check from start bit to the end of the byte */
+ if ((*lpOut &
+ ((0xff << (ulStart & 7))) & 0xff) != ((0xff << (ulStart & 7) & 0xff)))
+ return FALSE;
+ lpOut++;
+ ulCount -= (8 - (ulStart & 7));
+ }
+ else
+ {
+ /* Check from the start bit, possibly into the next byte also */
+ USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
+
+ if ((*lpOut & (initialWord & 0xff)) != (initialWord & 0xff))
+ return FALSE;
+ if ((initialWord & 0xff00) &&
+ ((lpOut[1] & (initialWord >> 8)) != (initialWord >> 8)))
+ return FALSE;
+ return TRUE;
+ }
+ }
+
+ /* Check bits in blocks of 8 bytes */
+ ulRemainder = ulCount & 7;
+ ulCount >>= 3;
+ while (ulCount--)
+ {
+ if (*lpOut++ != 0xff)
+ return FALSE;
+ }
+
+ /* Check remaining bits, if any */
+ if (ulRemainder &&
+ (*lpOut & NTDLL_maskBits[ulRemainder]) != NTDLL_maskBits[ulRemainder])
+ return FALSE;
+ return TRUE;
+}
+
+/*************************************************************************
+ * RtlAreBitsClear [NTDLL.@]
+ *
+ * Determine if part of a bitmap is clear.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulStart [I] First bit to check from
+ * ulCount [I] Number of consecutive bits to check
+ *
+ * RETURNS
+ * TRUE, If ulCount bits from ulStart are clear.
+ * FALSE, Otherwise.
+ */
+BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
+{
+ LPBYTE lpOut;
+ ULONG ulRemainder;
+
+ TRACE("(%p,%u,%u)\n", lpBits, ulStart, ulCount);
+
+ if (!lpBits || !ulCount ||
+ ulStart >= lpBits->SizeOfBitMap ||
+ ulCount > lpBits->SizeOfBitMap - ulStart)
+ return FALSE;
+
+ /* FIXME: It might be more efficient/cleaner to manipulate four bytes
+ * at a time. But beware of the pointer arithmetics...
+ */
+ lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
+
+ /* Check bits in first byte, if ulStart isn't a byte boundary */
+ if (ulStart & 7)
+ {
+ if (ulCount > 7)
+ {
+ /* Check from start bit to the end of the byte */
+ if (*lpOut & ((0xff << (ulStart & 7)) & 0xff))
+ return FALSE;
+ lpOut++;
+ ulCount -= (8 - (ulStart & 7));
+ }
+ else
+ {
+ /* Check from the start bit, possibly into the next byte also */
+ USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
+
+ if (*lpOut & (initialWord & 0xff))
+ return FALSE;
+ if ((initialWord & 0xff00) && (lpOut[1] & (initialWord >> 8)))
+ return FALSE;
+ return TRUE;
+ }
+ }
+
+ /* Check bits in blocks of 8 bytes */
+ ulRemainder = ulCount & 7;
+ ulCount >>= 3;
+ while (ulCount--)
+ {
+ if (*lpOut++)
+ return FALSE;
+ }
+
+ /* Check remaining bits, if any */
+ if (ulRemainder && *lpOut & NTDLL_maskBits[ulRemainder])
+ return FALSE;
+ return TRUE;
+}
+
+/*************************************************************************
+ * RtlFindSetBits [NTDLL.@]
+ *
+ * Find a block of set bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulCount [I] Number of consecutive set bits to find
+ * ulHint [I] Suggested starting position for set bits
+ *
+ * RETURNS
+ * The bit at which the match was found, or -1 if no match was found.
+ */
+ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
+{
+ ULONG ulPos, ulEnd;
+
+ TRACE("(%p,%u,%u)\n", lpBits, ulCount, ulHint);
+
+ if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
+ return ~0U;
+
+ ulEnd = lpBits->SizeOfBitMap;
+
+ if (ulHint + ulCount > lpBits->SizeOfBitMap)
+ ulHint = 0;
+
+ ulPos = ulHint;
+
+ while (ulPos < ulEnd)
+ {
+ /* FIXME: This could be made a _lot_ more efficient */
+ if (RtlAreBitsSet(lpBits, ulPos, ulCount))
+ return ulPos;
+
+ /* Start from the beginning if we hit the end and had a hint */
+ if (ulPos == ulEnd - 1 && ulHint)
+ {
+ ulEnd = ulHint;
+ ulPos = ulHint = 0;
+ }
+ else
+ ulPos++;
+ }
+ return ~0U;
+}
+
+/*************************************************************************
+ * RtlFindClearBits [NTDLL.@]
+ *
+ * Find a block of clear bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulCount [I] Number of consecutive clear bits to find
+ * ulHint [I] Suggested starting position for clear bits
+ *
+ * RETURNS
+ * The bit at which the match was found, or -1 if no match was found.
+ */
+ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
+{
+ ULONG ulPos, ulEnd;
+
+ TRACE("(%p,%u,%u)\n", lpBits, ulCount, ulHint);
+
+ if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
+ return ~0U;
+
+ ulEnd = lpBits->SizeOfBitMap;
+
+ if (ulHint + ulCount > lpBits->SizeOfBitMap)
+ ulHint = 0;
+
+ ulPos = ulHint;
+
+ while (ulPos < ulEnd)
+ {
+ /* FIXME: This could be made a _lot_ more efficient */
+ if (RtlAreBitsClear(lpBits, ulPos, ulCount))
+ return ulPos;
+
+ /* Start from the beginning if we hit the end and started from ulHint */
+ if (ulPos == ulEnd - 1 && ulHint)
+ {
+ ulEnd = ulHint;
+ ulPos = ulHint = 0;
+ }
+ else
+ ulPos++;
+ }
+ return ~0U;
+}
+
+/*************************************************************************
+ * RtlFindSetBitsAndClear [NTDLL.@]
+ *
+ * Find a block of set bits in a bitmap, and clear them if found.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulCount [I] Number of consecutive set bits to find
+ * ulHint [I] Suggested starting position for set bits
+ *
+ * RETURNS
+ * The bit at which the match was found, or -1 if no match was found.
+ */
+ULONG WINAPI RtlFindSetBitsAndClear(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
+{
+ ULONG ulPos;
+
+ TRACE("(%p,%u,%u)\n", lpBits, ulCount, ulHint);
+
+ ulPos = RtlFindSetBits(lpBits, ulCount, ulHint);
+ if (ulPos != ~0U)
+ RtlClearBits(lpBits, ulPos, ulCount);
+ return ulPos;
+}
+
+/*************************************************************************
+ * RtlFindClearBitsAndSet [NTDLL.@]
+ *
+ * Find a block of clear bits in a bitmap, and set them if found.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulCount [I] Number of consecutive clear bits to find
+ * ulHint [I] Suggested starting position for clear bits
+ *
+ * RETURNS
+ * The bit at which the match was found, or -1 if no match was found.
+ */
+ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
+{
+ ULONG ulPos;
+
+ TRACE("(%p,%u,%u)\n", lpBits, ulCount, ulHint);
+
+ ulPos = RtlFindClearBits(lpBits, ulCount, ulHint);
+ if (ulPos != ~0U)
+ RtlSetBits(lpBits, ulPos, ulCount);
+ return ulPos;
+}
+
+/*************************************************************************
+ * RtlNumberOfSetBits [NTDLL.@]
+ *
+ * Find the number of set bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ *
+ * RETURNS
+ * The number of set bits.
+ */
+ULONG WINAPI RtlNumberOfSetBits(PCRTL_BITMAP lpBits)
+{
+ ULONG ulSet = 0;
+
+ TRACE("(%p)\n", lpBits);
+
+ if (lpBits)
+ {
+ LPBYTE lpOut = (BYTE *)lpBits->Buffer;
+ ULONG ulCount, ulRemainder;
+ BYTE bMasked;
+
+ ulCount = lpBits->SizeOfBitMap >> 3;
+ ulRemainder = lpBits->SizeOfBitMap & 0x7;
+
+ while (ulCount--)
+ {
+ ulSet += NTDLL_nibbleBitCount[*lpOut >> 4];
+ ulSet += NTDLL_nibbleBitCount[*lpOut & 0xf];
+ lpOut++;
+ }
+
+ if (ulRemainder)
+ {
+ bMasked = *lpOut & NTDLL_maskBits[ulRemainder];
+ ulSet += NTDLL_nibbleBitCount[bMasked >> 4];
+ ulSet += NTDLL_nibbleBitCount[bMasked & 0xf];
+ }
+ }
+ return ulSet;
+}
+
+/*************************************************************************
+ * RtlNumberOfClearBits [NTDLL.@]
+ *
+ * Find the number of clear bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ *
+ * RETURNS
+ * The number of clear bits.
+ */
+ULONG WINAPI RtlNumberOfClearBits(PCRTL_BITMAP lpBits)
+{
+ TRACE("(%p)\n", lpBits);
+
+ if (lpBits)
+ return lpBits->SizeOfBitMap - RtlNumberOfSetBits(lpBits);
+ return 0;
+}
+
+/*************************************************************************
+ * RtlFindMostSignificantBit [NTDLL.@]
+ *
+ * Find the most significant bit in a 64 bit integer.
+ *
+ * RETURNS
+ * The position of the most significant bit.
+ */
+CCHAR WINAPI RtlFindMostSignificantBit(ULONGLONG ulLong)
+{
+ signed char ret = 32;
+ DWORD dw;
+
+ if (!(dw = (ulLong >> 32)))
+ {
+ ret = 0;
+ dw = (DWORD)ulLong;
+ }
+ if (dw & 0xffff0000)
+ {
+ dw >>= 16;
+ ret += 16;
+ }
+ if (dw & 0xff00)
+ {
+ dw >>= 8;
+ ret += 8;
+ }
+ if (dw & 0xf0)
+ {
+ dw >>= 4;
+ ret += 4;
+ }
+ return ret + NTDLL_mostSignificant[dw];
+}
+
+/*************************************************************************
+ * RtlFindLeastSignificantBit [NTDLL.@]
+ *
+ * Find the least significant bit in a 64 bit integer.
+ *
+ * RETURNS
+ * The position of the least significant bit.
+ */
+CCHAR WINAPI RtlFindLeastSignificantBit(ULONGLONG ulLong)
+{
+ signed char ret = 0;
+ DWORD dw;
+
+ if (!(dw = (DWORD)ulLong))
+ {
+ ret = 32;
+ if (!(dw = ulLong >> 32)) return -1;
+ }
+ if (!(dw & 0xffff))
+ {
+ dw >>= 16;
+ ret += 16;
+ }
+ if (!(dw & 0xff))
+ {
+ dw >>= 8;
+ ret += 8;
+ }
+ if (!(dw & 0x0f))
+ {
+ dw >>= 4;
+ ret += 4;
+ }
+ return ret + NTDLL_leastSignificant[dw & 0x0f];
+}
+
+/*************************************************************************
+ * NTDLL_RunSortFn
+ *
+ * Internal helper: qsort comparison function for RTL_BITMAP_RUN arrays
+ */
+static int NTDLL_RunSortFn(const void *lhs, const void *rhs)
+{
+ if (((const RTL_BITMAP_RUN*)lhs)->NumberOfBits > ((const RTL_BITMAP_RUN*)rhs)->NumberOfBits)
+ return -1;
+ return 1;
+}
+
+/*************************************************************************
+ * NTDLL_FindSetRun
+ *
+ * Internal helper: Find the next run of set bits in a bitmap.
+ */
+static ULONG NTDLL_FindSetRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
+{
+ LPBYTE lpOut;
+ ULONG ulFoundAt = 0, ulCount = 0;
+
+ /* FIXME: It might be more efficient/cleaner to manipulate four bytes
+ * at a time. But beware of the pointer arithmetics...
+ */
+ lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
+
+ while (1)
+ {
+ /* Check bits in first byte */
+ const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
+ const BYTE bFirst = *lpOut & bMask;
+
+ if (bFirst)
+ {
+ /* Have a set bit in first byte */
+ if (bFirst != bMask)
+ {
+ /* Not every bit is set */
+ ULONG ulOffset;
+
+ if (bFirst & 0x0f)
+ ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
+ else
+ ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
+ ulStart += ulOffset;
+ ulFoundAt = ulStart;
+ for (;ulOffset < 8; ulOffset++)
+ {
+ if (!(bFirst & (1 << ulOffset)))
+ {
+ *lpSize = ulCount;
+ return ulFoundAt; /* Set from start, but not until the end */
+ }
+ ulCount++;
+ ulStart++;
+ }
+ /* Set to the end - go on to count further bits */
+ lpOut++;
+ break;
+ }
+ /* every bit from start until the end of the byte is set */
+ ulFoundAt = ulStart;
+ ulCount = 8 - (ulStart & 7);
+ ulStart = (ulStart & ~7u) + 8;
+ lpOut++;
+ break;
+ }
+ ulStart = (ulStart & ~7u) + 8;
+ lpOut++;
+ if (ulStart >= lpBits->SizeOfBitMap)
+ return ~0U;
+ }
+
+ /* Check if reached the end of bitmap */
+ if (ulStart >= lpBits->SizeOfBitMap) {
+ *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
+ return ulFoundAt;
+ }
+
+ /* Count blocks of 8 set bits */
+ while (*lpOut == 0xff)
+ {
+ ulCount += 8;
+ ulStart += 8;
+ if (ulStart >= lpBits->SizeOfBitMap)
+ {
+ *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
+ return ulFoundAt;
+ }
+ lpOut++;
+ }
+
+ /* Count remaining contiguous bits, if any */
+ if (*lpOut & 1)
+ {
+ ULONG ulOffset = 0;
+
+ for (;ulOffset < 7u; ulOffset++)
+ {
+ if (!(*lpOut & (1 << ulOffset)))
+ break;
+ ulCount++;
+ }
+ }
+ *lpSize = ulCount;
+ return ulFoundAt;
+}
+
+/*************************************************************************
+ * NTDLL_FindClearRun
+ *
+ * Internal helper: Find the next run of set bits in a bitmap.
+ */
+static ULONG NTDLL_FindClearRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
+{
+ LPBYTE lpOut;
+ ULONG ulFoundAt = 0, ulCount = 0;
+
+ /* FIXME: It might be more efficient/cleaner to manipulate four bytes
+ * at a time. But beware of the pointer arithmetics...
+ */
+ lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
+
+ while (1)
+ {
+ /* Check bits in first byte */
+ const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
+ const BYTE bFirst = (~*lpOut) & bMask;
+
+ if (bFirst)
+ {
+ /* Have a clear bit in first byte */
+ if (bFirst != bMask)
+ {
+ /* Not every bit is clear */
+ ULONG ulOffset;
+
+ if (bFirst & 0x0f)
+ ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
+ else
+ ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
+ ulStart += ulOffset;
+ ulFoundAt = ulStart;
+ for (;ulOffset < 8; ulOffset++)
+ {
+ if (!(bFirst & (1 << ulOffset)))
+ {
+ *lpSize = ulCount;
+ return ulFoundAt; /* Clear from start, but not until the end */
+ }
+ ulCount++;
+ ulStart++;
+ }
+ /* Clear to the end - go on to count further bits */
+ lpOut++;
+ break;
+ }
+ /* Every bit from start until the end of the byte is clear */
+ ulFoundAt = ulStart;
+ ulCount = 8 - (ulStart & 7);
+ ulStart = (ulStart & ~7u) + 8;
+ lpOut++;
+ break;
+ }
+ ulStart = (ulStart & ~7u) + 8;
+ lpOut++;
+ if (ulStart >= lpBits->SizeOfBitMap)
+ return ~0U;
+ }
+
+ /* Check if reached the end of bitmap */
+ if (ulStart >= lpBits->SizeOfBitMap) {
+ *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
+ return ulFoundAt;
+ }
+
+ /* Count blocks of 8 clear bits */
+ while (!*lpOut)
+ {
+ ulCount += 8;
+ ulStart += 8;
+ if (ulStart >= lpBits->SizeOfBitMap)
+ {
+ *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
+ return ulFoundAt;
+ }
+ lpOut++;
+ }
+
+ /* Count remaining contiguous bits, if any */
+ if (!(*lpOut & 1))
+ {
+ ULONG ulOffset = 0;
+
+ for (;ulOffset < 7u; ulOffset++)
+ {
+ if (*lpOut & (1 << ulOffset))
+ break;
+ ulCount++;
+ }
+ }
+ *lpSize = ulCount;
+ return ulFoundAt;
+}
+
+/*************************************************************************
+ * RtlFindNextForwardRunSet [NTDLL.@]
+ *
+ * Find the next run of set bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulStart [I] Bit position to start searching from
+ * lpPos [O] Start of run
+ *
+ * RETURNS
+ * Success: The length of the next set run in the bitmap. lpPos is set to
+ * the start of the run.
+ * Failure: 0, if no run is found or any parameters are invalid.
+ */
+ULONG WINAPI RtlFindNextForwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
+{
+ ULONG ulSize = 0;
+
+ TRACE("(%p,%u,%p)\n", lpBits, ulStart, lpPos);
+
+ if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
+ *lpPos = NTDLL_FindSetRun(lpBits, ulStart, &ulSize);
+
+ return ulSize;
+}
+
+/*************************************************************************
+ * RtlFindNextForwardRunClear [NTDLL.@]
+ *
+ * Find the next run of clear bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulStart [I] Bit position to start searching from
+ * lpPos [O] Start of run
+ *
+ * RETURNS
+ * Success: The length of the next clear run in the bitmap. lpPos is set to
+ * the start of the run.
+ * Failure: 0, if no run is found or any parameters are invalid.
+ */
+ULONG WINAPI RtlFindNextForwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
+{
+ ULONG ulSize = 0;
+
+ TRACE("(%p,%u,%p)\n", lpBits, ulStart, lpPos);
+
+ if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
+ *lpPos = NTDLL_FindClearRun(lpBits, ulStart, &ulSize);
+
+ return ulSize;
+}
+
+/*************************************************************************
+ * RtlFindLastBackwardRunSet [NTDLL.@]
+ *
+ * Find a previous run of set bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulStart [I] Bit position to start searching from
+ * lpPos [O] Start of run
+ *
+ * RETURNS
+ * Success: The length of the previous set run in the bitmap. lpPos is set to
+ * the start of the run.
+ * Failure: 0, if no run is found or any parameters are invalid.
+ */
+ULONG WINAPI RtlFindLastBackwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
+{
+ FIXME("(%p,%u,%p)-stub!\n", lpBits, ulStart, lpPos);
+ return 0;
+}
+
+/*************************************************************************
+ * RtlFindLastBackwardRunClear [NTDLL.@]
+ *
+ * Find a previous run of clear bits in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulStart [I] Bit position to start searching from
+ * lpPos [O] Start of run
+ *
+ * RETURNS
+ * Success: The length of the previous clear run in the bitmap. lpPos is set
+ * to the start of the run.
+ * Failure: 0, if no run is found or any parameters are invalid.
+ */
+ULONG WINAPI RtlFindLastBackwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
+{
+ FIXME("(%p,%u,%p)-stub!\n", lpBits, ulStart, lpPos);
+ return 0;
+}
+
+/*************************************************************************
+ * NTDLL_FindRuns
+ *
+ * Internal implementation of RtlFindSetRuns/RtlFindClearRuns.
+ */
+static ULONG NTDLL_FindRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
+ ULONG ulCount, BOOLEAN bLongest,
+ ULONG (*fn)(PCRTL_BITMAP,ULONG,PULONG))
+{
+ BOOL bNeedSort = ulCount > 1;
+ ULONG ulPos = 0, ulRuns = 0;
+
+ TRACE("(%p,%p,%d,%d)\n", lpBits, lpSeries, ulCount, bLongest);
+
+ if (!ulCount)
+ return ~0U;
+
+ while (ulPos < lpBits->SizeOfBitMap)
+ {
+ /* Find next set/clear run */
+ ULONG ulSize, ulNextPos = fn(lpBits, ulPos, &ulSize);
+
+ if (ulNextPos == ~0U)
+ break;
+
+ if (bLongest && ulRuns == ulCount)
+ {
+ /* Sort runs with shortest at end, if they are out of order */
+ if (bNeedSort)
+ qsort(lpSeries, ulRuns, sizeof(RTL_BITMAP_RUN), NTDLL_RunSortFn);
+
+ /* Replace last run if this one is bigger */
+ if (ulSize > lpSeries[ulRuns - 1].NumberOfBits)
+ {
+ lpSeries[ulRuns - 1].StartingIndex = ulNextPos;
+ lpSeries[ulRuns - 1].NumberOfBits = ulSize;
+
+ /* We need to re-sort the array, _if_ we didn't leave it sorted */
+ if (ulRuns > 1 && ulSize > lpSeries[ulRuns - 2].NumberOfBits)
+ bNeedSort = TRUE;
+ }
+ }
+ else
+ {
+ /* Append to found runs */
+ lpSeries[ulRuns].StartingIndex = ulNextPos;
+ lpSeries[ulRuns].NumberOfBits = ulSize;
+ ulRuns++;
+
+ if (!bLongest && ulRuns == ulCount)
+ break;
+ }
+ ulPos = ulNextPos + ulSize;
+ }
+ return ulRuns;
+}
+
+/*************************************************************************
+ * RtlFindSetRuns [NTDLL.@]
+ *
+ * Find a series of set runs in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * lpSeries [O] Array for each run found
+ * ulCount [I] Number of runs to find
+ * bLongest [I] Whether to find the very longest runs or not
+ *
+ * RETURNS
+ * The number of set runs found.
+ */
+ULONG WINAPI RtlFindSetRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
+ ULONG ulCount, BOOLEAN bLongest)
+{
+ TRACE("(%p,%p,%u,%d)\n", lpBits, lpSeries, ulCount, bLongest);
+
+ return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindSetRun);
+}
+
+/*************************************************************************
+ * RtlFindClearRuns [NTDLL.@]
+ *
+ * Find a series of clear runs in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * ulSeries [O] Array for each run found
+ * ulCount [I] Number of runs to find
+ * bLongest [I] Whether to find the very longest runs or not
+ *
+ * RETURNS
+ * The number of clear runs found.
+ */
+ULONG WINAPI RtlFindClearRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
+ ULONG ulCount, BOOLEAN bLongest)
+{
+ TRACE("(%p,%p,%u,%d)\n", lpBits, lpSeries, ulCount, bLongest);
+
+ return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindClearRun);
+}
+
+/*************************************************************************
+ * RtlFindLongestRunSet [NTDLL.@]
+ *
+ * Find the longest set run in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * pulStart [O] Destination for start of run
+ *
+ * RETURNS
+ * The length of the run found, or 0 if no run is found.
+ */
+ULONG WINAPI RtlFindLongestRunSet(PCRTL_BITMAP lpBits, PULONG pulStart)
+{
+ RTL_BITMAP_RUN br;
+
+ TRACE("(%p,%p)\n", lpBits, pulStart);
+
+ if (RtlFindSetRuns(lpBits, &br, 1, TRUE) == 1)
+ {
+ if (pulStart)
+ *pulStart = br.StartingIndex;
+ return br.NumberOfBits;
+ }
+ return 0;
+}
+
+/*************************************************************************
+ * RtlFindLongestRunClear [NTDLL.@]
+ *
+ * Find the longest clear run in a bitmap.
+ *
+ * PARAMS
+ * lpBits [I] Bitmap pointer
+ * pulStart [O] Destination for start of run
+ *
+ * RETURNS
+ * The length of the run found, or 0 if no run is found.
+ */
+ULONG WINAPI RtlFindLongestRunClear(PCRTL_BITMAP lpBits, PULONG pulStart)
+{
+ RTL_BITMAP_RUN br;
+
+ TRACE("(%p,%p)\n", lpBits, pulStart);
+
+ if (RtlFindClearRuns(lpBits, &br, 1, TRUE) == 1)
+ {
+ if (pulStart)
+ *pulStart = br.StartingIndex;
+ return br.NumberOfBits;
+ }
+ return 0;
+}
+
+DECLARE_CRT_EXPORT("RtlFindClearBitsAndSet", RtlFindClearBitsAndSet);
+DECLARE_CRT_EXPORT("RtlClearBits", RtlClearBits);
+DECLARE_CRT_EXPORT("RtlAreBitsSet", RtlAreBitsSet);
diff --git a/peloader/winnt_types.h b/peloader/winnt_types.h
index 1475a48..cc80c08 100644
--- a/peloader/winnt_types.h
+++ b/peloader/winnt_types.h
@@ -25,6 +25,7 @@
#define FALSE 0
#define HANDLE PVOID
+#define HMODULE PVOID
#define INVALID_HANDLE_VALUE ((HANDLE)(-1))
#define PASSIVE_LEVEL 0
@@ -134,6 +135,7 @@
#define WINAPI __attribute__((__stdcall__))
#define KI_USER_SHARED_DATA 0xffdf0000
+#define MM_SHARED_USER_DATA_VA 0x7ffe0000
typedef uint8_t BOOLEAN, BOOL;
typedef void *PVOID;
@@ -192,11 +194,11 @@ typedef struct _FILETIME {
DWORD dwHighDateTime;
} FILETIME, *PFILETIME;
-struct ansi_string {
+typedef struct ansi_string {
USHORT length;
USHORT max_length;
char *buf;
-};
+} ANSI_STRING, *PANSI_STRING;
typedef struct unicode_string {
USHORT Length;
@@ -1440,7 +1442,21 @@ typedef struct _EXCEPTION_FRAME {
PEXCEPTION_HANDLER handler;
} EXCEPTION_FRAME, *PEXCEPTION_FRAME;
-struct kuser_shared_data {
+typedef struct _RTL_BITMAP {
+ ULONG SizeOfBitMap;
+ LPBYTE Buffer;
+} RTL_BITMAP, *PRTL_BITMAP;
+
+typedef const RTL_BITMAP *PCRTL_BITMAP;
+
+typedef struct _RTL_BITMAP_RUN {
+ ULONG StartingIndex;
+ ULONG NumberOfBits;
+} RTL_BITMAP_RUN, *PRTL_BITMAP_RUN;
+
+typedef const RTL_BITMAP_RUN *PCRTL_BITMAP_RUN;
+
+typedef struct _KUSER_SHARED_DATA {
ULONG tick_count;
ULONG tick_count_multiplier;
volatile struct ksystem_time interrupt_time;
@@ -1479,7 +1495,7 @@ struct kuser_shared_data {
volatile struct ksystem_time tick_count;
volatile ULONG64 tick_count_quad;
} tick;
-};
+} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
#define REG_NONE (0)
#define REG_SZ (1)