diff options
author | Tavis Ormandy <taviso@gmail.com> | 2020-03-02 08:06:28 +0300 |
---|---|---|
committer | Tavis Ormandy <taviso@gmail.com> | 2020-03-02 08:06:28 +0300 |
commit | 3b76c18a146b880087491f15b0038ef838c9a928 (patch) | |
tree | 06e6c649a7fd6421ec8fa172edbb63069fd2344e | |
parent | a4379b27b4bbcc5069b467c2928e94433661de17 (diff) |
testing support for more engines
-rw-r--r-- | .gdbinit | 85 | ||||
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 13 | ||||
-rw-r--r-- | peloader/pe_linker.c | 33 | ||||
-rw-r--r-- | peloader/pe_linker.h | 79 | ||||
-rw-r--r-- | peloader/winapi/Heap.c | 29 | ||||
-rw-r--r-- | peloader/winapi/Internal.c | 77 | ||||
-rw-r--r-- | peloader/winapi/rtlbitmap.c | 1129 | ||||
-rw-r--r-- | peloader/winnt_types.h | 24 |
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 @@ -5,4 +5,5 @@ *.vdm *.exe mpclient -mpscript +avscript +eicar.com @@ -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) |