Skip to content

Instantly share code, notes, and snippets.

@shmuelfomberg
Last active November 30, 2017 09:26
Show Gist options
  • Save shmuelfomberg/231b685d39e4d52c10f8a4ef4c88da75 to your computer and use it in GitHub Desktop.
Save shmuelfomberg/231b685d39e4d52c10f8a4ef4c88da75 to your computer and use it in GitHub Desktop.
Wow64Ext_ShowSnap
An exmaple of the crash with Wow64Ext and Loader ShowSnaps active
Runs OK as is.
When importing the registry file: (activating Loader Show Snaps)
Runs OK in the debugger
Crashes when runned without debugger
The crash is inside GetProcAddress64.
#include "stdafx.h"
#include <Windows.h>
/**
*
* WOW64Ext Library
*
* Copyright (c) 2014 ReWolf
* http://blog.rewolf.pl/
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <cstddef>
#include <stdlib.h>
#define EMIT(a) __asm __emit (a)
#define X64_Start_with_CS(_cs) \
{ \
EMIT(0x6A) EMIT(_cs) /* push _cs */ \
EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \
EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(5) /* add dword [esp], 5 */ \
EMIT(0xCB) /* retf */ \
}
#define X64_End_with_CS(_cs) \
{ \
EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \
EMIT(0xC7) EMIT(0x44) EMIT(0x24) EMIT(4) EMIT(_cs) EMIT(0) EMIT(0) EMIT(0) /* mov dword [rsp + 4], _cs */ \
EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(0xD) /* add dword [rsp], 0xD */ \
EMIT(0xCB) /* retf */ \
}
#define X64_Start() X64_Start_with_CS(0x33)
#define X64_End() X64_End_with_CS(0x23)
#define _RAX 0
#define _RCX 1
#define _RDX 2
#define _RBX 3
#define _RSP 4
#define _RBP 5
#define _RSI 6
#define _RDI 7
#define _R8 8
#define _R9 9
#define _R10 10
#define _R11 11
#define _R12 12
#define _R13 13
#define _R14 14
#define _R15 15
#define X64_Push(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x50 | ((r) & 7))
#define X64_Pop(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x58 | ((r) & 7))
#define REX_W EMIT(0x48) __asm
//to fool M$ inline asm compiler I'm using 2 DWORDs instead of DWORD64
//use of DWORD64 will generate wrong 'pop word ptr[]' and it will break stack
union reg64
{
DWORD64 v;
DWORD dw[2];
};
class CMemPtr
{
private:
void** m_ptr;
bool watchActive;
public:
CMemPtr(void** ptr) : m_ptr(ptr), watchActive(true) {}
~CMemPtr()
{
if (*m_ptr && watchActive)
{
free(*m_ptr);
*m_ptr = 0;
}
}
void disableWatch() { watchActive = false; }
};
#define WATCH(ptr) \
CMemPtr watch_##ptr((void**)&ptr)
#define DISABLE_WATCH(ptr) \
watch_##ptr.disableWatch()
#ifndef STATUS_SUCCESS
# define STATUS_SUCCESS 0
#endif
#pragma pack(push)
#pragma pack(1)
template <class T>
struct _LIST_ENTRY_T
{
T Flink;
T Blink;
};
template <class T>
struct _UNICODE_STRING_T
{
union
{
struct
{
WORD Length;
WORD MaximumLength;
};
T dummy;
};
T Buffer;
};
template <class T>
struct _NT_TIB_T
{
T ExceptionList;
T StackBase;
T StackLimit;
T SubSystemTib;
T FiberData;
T ArbitraryUserPointer;
T Self;
};
template <class T>
struct _CLIENT_ID
{
T UniqueProcess;
T UniqueThread;
};
template <class T>
struct _TEB_T_
{
_NT_TIB_T<T> NtTib;
T EnvironmentPointer;
_CLIENT_ID<T> ClientId;
T ActiveRpcHandle;
T ThreadLocalStoragePointer;
T ProcessEnvironmentBlock;
DWORD LastErrorValue;
DWORD CountOfOwnedCriticalSections;
T CsrClientThread;
T Win32ThreadInfo;
DWORD User32Reserved[26];
//rest of the structure is not defined for now, as it is not needed
};
template <class T>
struct _LDR_DATA_TABLE_ENTRY_T
{
_LIST_ENTRY_T<T> InLoadOrderLinks;
_LIST_ENTRY_T<T> InMemoryOrderLinks;
_LIST_ENTRY_T<T> InInitializationOrderLinks;
T DllBase;
T EntryPoint;
union
{
DWORD SizeOfImage;
T dummy01;
};
_UNICODE_STRING_T<T> FullDllName;
_UNICODE_STRING_T<T> BaseDllName;
DWORD Flags;
WORD LoadCount;
WORD TlsIndex;
union
{
_LIST_ENTRY_T<T> HashLinks;
struct
{
T SectionPointer;
T CheckSum;
};
};
union
{
T LoadedImports;
DWORD TimeDateStamp;
};
T EntryPointActivationContext;
T PatchInformation;
_LIST_ENTRY_T<T> ForwarderLinks;
_LIST_ENTRY_T<T> ServiceTagLinks;
_LIST_ENTRY_T<T> StaticLinks;
T ContextInformation;
T OriginalBase;
_LARGE_INTEGER LoadTime;
};
template <class T>
struct _PEB_LDR_DATA_T
{
DWORD Length;
DWORD Initialized;
T SsHandle;
_LIST_ENTRY_T<T> InLoadOrderModuleList;
_LIST_ENTRY_T<T> InMemoryOrderModuleList;
_LIST_ENTRY_T<T> InInitializationOrderModuleList;
T EntryInProgress;
DWORD ShutdownInProgress;
T ShutdownThreadId;
};
template <class T, class NGF, int A>
struct _PEB_T
{
union
{
struct
{
BYTE InheritedAddressSpace;
BYTE ReadImageFileExecOptions;
BYTE BeingDebugged;
BYTE BitField;
};
T dummy01;
};
T Mutant;
T ImageBaseAddress;
T Ldr;
T ProcessParameters;
T SubSystemData;
T ProcessHeap;
T FastPebLock;
T AtlThunkSListPtr;
T IFEOKey;
T CrossProcessFlags;
T UserSharedInfoPtr;
DWORD SystemReserved;
DWORD AtlThunkSListPtr32;
T ApiSetMap;
T TlsExpansionCounter;
T TlsBitmap;
DWORD TlsBitmapBits[2];
T ReadOnlySharedMemoryBase;
T HotpatchInformation;
T ReadOnlyStaticServerData;
T AnsiCodePageData;
T OemCodePageData;
T UnicodeCaseTableData;
DWORD NumberOfProcessors;
union
{
DWORD NtGlobalFlag;
NGF dummy02;
};
LARGE_INTEGER CriticalSectionTimeout;
T HeapSegmentReserve;
T HeapSegmentCommit;
T HeapDeCommitTotalFreeThreshold;
T HeapDeCommitFreeBlockThreshold;
DWORD NumberOfHeaps;
DWORD MaximumNumberOfHeaps;
T ProcessHeaps;
T GdiSharedHandleTable;
T ProcessStarterHelper;
T GdiDCAttributeList;
T LoaderLock;
DWORD OSMajorVersion;
DWORD OSMinorVersion;
WORD OSBuildNumber;
WORD OSCSDVersion;
DWORD OSPlatformId;
DWORD ImageSubsystem;
DWORD ImageSubsystemMajorVersion;
T ImageSubsystemMinorVersion;
T ActiveProcessAffinityMask;
T GdiHandleBuffer[A];
T PostProcessInitRoutine;
T TlsExpansionBitmap;
DWORD TlsExpansionBitmapBits[32];
T SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
T pShimData;
T AppCompatInfo;
_UNICODE_STRING_T<T> CSDVersion;
T ActivationContextData;
T ProcessAssemblyStorageMap;
T SystemDefaultActivationContextData;
T SystemAssemblyStorageMap;
T MinimumStackCommit;
T FlsCallback;
_LIST_ENTRY_T<T> FlsListHead;
T FlsBitmap;
DWORD FlsBitmapBits[4];
T FlsHighIndex;
T WerRegistrationData;
T WerShipAssertPtr;
T pContextData;
T pImageHeaderHash;
T TracingFlags;
};
typedef _LDR_DATA_TABLE_ENTRY_T<DWORD> LDR_DATA_TABLE_ENTRY32;
typedef _LDR_DATA_TABLE_ENTRY_T<DWORD64> LDR_DATA_TABLE_ENTRY64;
typedef _TEB_T_<DWORD> TEB32;
typedef _TEB_T_<DWORD64> TEB64;
typedef _PEB_LDR_DATA_T<DWORD> PEB_LDR_DATA32;
typedef _PEB_LDR_DATA_T<DWORD64> PEB_LDR_DATA64;
typedef _PEB_T<DWORD, DWORD64, 34> PEB32;
typedef _PEB_T<DWORD64, DWORD, 30> PEB64;
struct _XSAVE_FORMAT64
{
WORD ControlWord;
WORD StatusWord;
BYTE TagWord;
BYTE Reserved1;
WORD ErrorOpcode;
DWORD ErrorOffset;
WORD ErrorSelector;
WORD Reserved2;
DWORD DataOffset;
WORD DataSelector;
WORD Reserved3;
DWORD MxCsr;
DWORD MxCsr_Mask;
_M128A FloatRegisters[8];
_M128A XmmRegisters[16];
BYTE Reserved4[96];
};
struct _CONTEXT64
{
DWORD64 P1Home;
DWORD64 P2Home;
DWORD64 P3Home;
DWORD64 P4Home;
DWORD64 P5Home;
DWORD64 P6Home;
DWORD ContextFlags;
DWORD MxCsr;
WORD SegCs;
WORD SegDs;
WORD SegEs;
WORD SegFs;
WORD SegGs;
WORD SegSs;
DWORD EFlags;
DWORD64 Dr0;
DWORD64 Dr1;
DWORD64 Dr2;
DWORD64 Dr3;
DWORD64 Dr6;
DWORD64 Dr7;
DWORD64 Rax;
DWORD64 Rcx;
DWORD64 Rdx;
DWORD64 Rbx;
DWORD64 Rsp;
DWORD64 Rbp;
DWORD64 Rsi;
DWORD64 Rdi;
DWORD64 R8;
DWORD64 R9;
DWORD64 R10;
DWORD64 R11;
DWORD64 R12;
DWORD64 R13;
DWORD64 R14;
DWORD64 R15;
DWORD64 Rip;
_XSAVE_FORMAT64 FltSave;
_M128A Header[2];
_M128A Legacy[8];
_M128A Xmm0;
_M128A Xmm1;
_M128A Xmm2;
_M128A Xmm3;
_M128A Xmm4;
_M128A Xmm5;
_M128A Xmm6;
_M128A Xmm7;
_M128A Xmm8;
_M128A Xmm9;
_M128A Xmm10;
_M128A Xmm11;
_M128A Xmm12;
_M128A Xmm13;
_M128A Xmm14;
_M128A Xmm15;
_M128A VectorRegister[26];
DWORD64 VectorControl;
DWORD64 DebugControl;
DWORD64 LastBranchToRip;
DWORD64 LastBranchFromRip;
DWORD64 LastExceptionToRip;
DWORD64 LastExceptionFromRip;
};
// Below defines for .ContextFlags field are taken from WinNT.h
#ifndef CONTEXT_AMD64
#define CONTEXT_AMD64 0x100000
#endif
#define CONTEXT64_CONTROL (CONTEXT_AMD64 | 0x1L)
#define CONTEXT64_INTEGER (CONTEXT_AMD64 | 0x2L)
#define CONTEXT64_SEGMENTS (CONTEXT_AMD64 | 0x4L)
#define CONTEXT64_FLOATING_POINT (CONTEXT_AMD64 | 0x8L)
#define CONTEXT64_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L)
#define CONTEXT64_FULL (CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_FLOATING_POINT)
#define CONTEXT64_ALL (CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_SEGMENTS | CONTEXT64_FLOATING_POINT | CONTEXT64_DEBUG_REGISTERS)
#define CONTEXT64_XSTATE (CONTEXT_AMD64 | 0x20L)
#pragma warning(push)
#pragma warning(disable : 4409)
extern "C" DWORD64 __cdecl X64Call(DWORD64 func, int argC, ...)
{
va_list args;
va_start(args, argC);
reg64 _rcx = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 };
reg64 _rdx = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 };
reg64 _r8 = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 };
reg64 _r9 = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 };
reg64 _rax = { 0 };
reg64 restArgs = { (DWORD64)&va_arg(args, DWORD64) };
// conversion to QWORD for easier use in inline assembly
reg64 _argC = { (DWORD64)argC };
DWORD back_esp = 0;
WORD back_fs = 0;
__asm
{
;// reset FS segment, to properly handle RFG
mov back_fs, fs
mov eax, 0x2B
mov fs, ax
;// keep original esp in back_esp variable
mov back_esp, esp
;// align esp to 0x10, without aligned stack some syscalls may return errors !
;// (actually, for syscalls it is sufficient to align to 8, but SSE opcodes
;// requires 0x10 alignment), it will be further adjusted according to the
;// number of arguments above 4
and esp, 0xFFFFFFF0
X64_Start();
;// below code is compiled as x86 inline asm, but it is executed as x64 code
;// that's why it need sometimes REX_W() macro, right column contains detailed
;// transcription how it will be interpreted by CPU
;// fill first four arguments
REX_W mov ecx, _rcx.dw[0];// mov rcx, qword ptr [_rcx]
REX_W mov edx, _rdx.dw[0];// mov rdx, qword ptr [_rdx]
push _r8.v;// push qword ptr [_r8]
X64_Pop(_R8); ;// pop r8
push _r9.v;// push qword ptr [_r9]
X64_Pop(_R9); ;// pop r9
;//
REX_W mov eax, _argC.dw[0];// mov rax, qword ptr [_argC]
;//
;// final stack adjustment, according to the ;//
;// number of arguments above 4 ;//
test al, 1;// test al, 1
jnz _no_adjust;// jnz _no_adjust
sub esp, 8;// sub rsp, 8
_no_adjust:;//
;//
push edi;// push rdi
REX_W mov edi, restArgs.dw[0];// mov rdi, qword ptr [restArgs]
;//
;// put rest of arguments on the stack ;//
REX_W test eax, eax;// test rax, rax
jz _ls_e;// je _ls_e
REX_W lea edi, dword ptr[edi + 8 * eax - 8];// lea rdi, [rdi + rax*8 - 8]
;//
_ls:;//
REX_W test eax, eax;// test rax, rax
jz _ls_e;// je _ls_e
push dword ptr[edi];// push qword ptr [rdi]
REX_W sub edi, 8;// sub rdi, 8
REX_W sub eax, 1;// sub rax, 1
jmp _ls;// jmp _ls
_ls_e:;//
;//
;// create stack space for spilling registers ;//
REX_W sub esp, 0x20;// sub rsp, 20h
;//
call func;// call qword ptr [func]
;//
;// cleanup stack ;//
REX_W mov ecx, _argC.dw[0];// mov rcx, qword ptr [_argC]
REX_W lea esp, dword ptr[esp + 8 * ecx + 0x20];// lea rsp, [rsp + rcx*8 + 20h]
;//
pop edi;// pop rdi
;//
// set return value ;//
REX_W mov _rax.dw[0], eax;// mov qword ptr [_rax], rax
X64_End();
mov ax, ds
mov ss, ax
mov esp, back_esp
;// restore FS segment
mov ax, back_fs
mov fs, ax
}
return _rax.v;
}
#pragma warning(pop)
void getMem64(void* dstMem, DWORD64 srcMem, size_t sz)
{
if ((nullptr == dstMem) || (0 == srcMem) || (0 == sz))
return;
reg64 _src = { srcMem };
__asm
{
X64_Start();
;// below code is compiled as x86 inline asm, but it is executed as x64 code
;// that's why it need sometimes REX_W() macro, right column contains detailed
;// transcription how it will be interpreted by CPU
push edi;// push rdi
push esi;// push rsi
;//
mov edi, dstMem;// mov edi, dword ptr [dstMem] ; high part of RDI is zeroed
REX_W mov esi, _src.dw[0];// mov rsi, qword ptr [_src]
mov ecx, sz;// mov ecx, dword ptr [sz] ; high part of RCX is zeroed
;//
mov eax, ecx;// mov eax, ecx
and eax, 3;// and eax, 3
shr ecx, 2;// shr ecx, 2
;//
rep movsd;// rep movs dword ptr [rdi], dword ptr [rsi]
;//
test eax, eax;// test eax, eax
je _move_0;// je _move_0
cmp eax, 1;// cmp eax, 1
je _move_1;// je _move_1
;//
movsw;// movs word ptr [rdi], word ptr [rsi]
cmp eax, 2;// cmp eax, 2
je _move_0;// je _move_0
;//
_move_1:;//
movsb;// movs byte ptr [rdi], byte ptr [rsi]
;//
_move_0:;//
pop esi;// pop rsi
pop edi;// pop rdi
X64_End();
}
}
bool cmpMem64(void* dstMem, DWORD64 srcMem, size_t sz)
{
if ((nullptr == dstMem) || (0 == srcMem) || (0 == sz))
return false;
bool result = false;
reg64 _src = { srcMem };
__asm
{
X64_Start();
;// below code is compiled as x86 inline asm, but it is executed as x64 code
;// that's why it need sometimes REX_W() macro, right column contains detailed
;// transcription how it will be interpreted by CPU
push edi;// push rdi
push esi;// push rsi
;//
mov edi, dstMem;// mov edi, dword ptr [dstMem] ; high part of RDI is zeroed
REX_W mov esi, _src.dw[0];// mov rsi, qword ptr [_src]
mov ecx, sz;// mov ecx, dword ptr [sz] ; high part of RCX is zeroed
;//
mov eax, ecx;// mov eax, ecx
and eax, 3;// and eax, 3
shr ecx, 2;// shr ecx, 2
;//
repe cmpsd;// repe cmps dword ptr [rsi], dword ptr [rdi]
jnz _ret_false;// jnz _ret_false
;//
test eax, eax;// test eax, eax
je _move_0;// je _move_0
cmp eax, 1;// cmp eax, 1
je _move_1;// je _move_1
;//
cmpsw;// cmps word ptr [rsi], word ptr [rdi]
jnz _ret_false;// jnz _ret_false
cmp eax, 2;// cmp eax, 2
je _move_0;// je _move_0
;//
_move_1:;//
cmpsb;// cmps byte ptr [rsi], byte ptr [rdi]
jnz _ret_false;// jnz _ret_false
;//
_move_0:;//
mov result, 1;// mov byte ptr [result], 1
;//
_ret_false:;//
pop esi;// pop rsi
pop edi;// pop rdi
X64_End();
}
return result;
}
DWORD64 getTEB64()
{
reg64 reg;
reg.v = 0;
X64_Start();
// R12 register should always contain pointer to TEB64 in WoW64 processes
X64_Push(_R12);
// below pop will pop QWORD from stack, as we're in x64 mode now
__asm pop reg.dw[0]
X64_End();
return reg.v;
}
extern "C" DWORD64 __cdecl GetModuleHandle64(wchar_t* lpModuleName)
{
TEB64 teb64;
getMem64(&teb64, getTEB64(), sizeof(TEB64));
PEB64 peb64;
getMem64(&peb64, teb64.ProcessEnvironmentBlock, sizeof(PEB64));
PEB_LDR_DATA64 ldr;
getMem64(&ldr, peb64.Ldr, sizeof(PEB_LDR_DATA64));
DWORD64 LastEntry = peb64.Ldr + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList);
LDR_DATA_TABLE_ENTRY64 head;
head.InLoadOrderLinks.Flink = ldr.InLoadOrderModuleList.Flink;
do
{
getMem64(&head, head.InLoadOrderLinks.Flink, sizeof(LDR_DATA_TABLE_ENTRY64));
wchar_t* tempBuf = (wchar_t*)malloc(head.BaseDllName.MaximumLength);
if (nullptr == tempBuf)
return 0;
WATCH(tempBuf);
getMem64(tempBuf, head.BaseDllName.Buffer, head.BaseDllName.MaximumLength);
if (0 == _wcsicmp(lpModuleName, tempBuf))
return head.DllBase;
} while (head.InLoadOrderLinks.Flink != LastEntry);
return 0;
}
DWORD64 getNTDLL64()
{
static DWORD64 ntdll64 = 0;
if (0 != ntdll64)
return ntdll64;
ntdll64 = GetModuleHandle64(L"ntdll.dll");
return ntdll64;
}
DWORD64 getLdrGetProcedureAddress()
{
DWORD64 modBase = getNTDLL64();
if (0 == modBase)
return 0;
IMAGE_DOS_HEADER idh;
getMem64(&idh, modBase, sizeof(idh));
IMAGE_NT_HEADERS64 inh;
getMem64(&inh, modBase + idh.e_lfanew, sizeof(IMAGE_NT_HEADERS64));
IMAGE_DATA_DIRECTORY& idd = inh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (0 == idd.VirtualAddress)
return 0;
IMAGE_EXPORT_DIRECTORY ied;
getMem64(&ied, modBase + idd.VirtualAddress, sizeof(ied));
DWORD* rvaTable = (DWORD*)malloc(sizeof(DWORD)*ied.NumberOfFunctions);
if (nullptr == rvaTable)
return 0;
WATCH(rvaTable);
getMem64(rvaTable, modBase + ied.AddressOfFunctions, sizeof(DWORD)*ied.NumberOfFunctions);
WORD* ordTable = (WORD*)malloc(sizeof(WORD)*ied.NumberOfFunctions);
if (nullptr == ordTable)
return 0;
WATCH(ordTable);
getMem64(ordTable, modBase + ied.AddressOfNameOrdinals, sizeof(WORD)*ied.NumberOfFunctions);
DWORD* nameTable = (DWORD*)malloc(sizeof(DWORD)*ied.NumberOfNames);
if (nullptr == nameTable)
return 0;
WATCH(nameTable);
getMem64(nameTable, modBase + ied.AddressOfNames, sizeof(DWORD)*ied.NumberOfNames);
// lazy search, there is no need to use binsearch for just one function
for (DWORD i = 0; i < ied.NumberOfFunctions; i++)
{
if (!cmpMem64("LdrGetProcedureAddress", modBase + nameTable[i], sizeof("LdrGetProcedureAddress")))
continue;
else
return modBase + rvaTable[ordTable[i]];
}
return 0;
}
extern "C" VOID __cdecl SetLastErrorFromX64Call(DWORD64 status)
{
typedef ULONG(WINAPI *RtlNtStatusToDosError_t)(NTSTATUS Status);
typedef ULONG(WINAPI *RtlSetLastWin32Error_t)(NTSTATUS Status);
static RtlNtStatusToDosError_t RtlNtStatusToDosError = nullptr;
static RtlSetLastWin32Error_t RtlSetLastWin32Error = nullptr;
if ((nullptr == RtlNtStatusToDosError) || (nullptr == RtlSetLastWin32Error))
{
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
RtlNtStatusToDosError = (RtlNtStatusToDosError_t)GetProcAddress(ntdll, "RtlNtStatusToDosError");
RtlSetLastWin32Error = (RtlSetLastWin32Error_t)GetProcAddress(ntdll, "RtlSetLastWin32Error");
}
if ((nullptr != RtlNtStatusToDosError) && (nullptr != RtlSetLastWin32Error))
{
RtlSetLastWin32Error(RtlNtStatusToDosError((DWORD)status));
}
}
static volatile int waitforme = 0;
extern "C" DWORD64 __cdecl GetProcAddress64(DWORD64 hModule, char* funcName)
{
static DWORD64 _LdrGetProcedureAddress = 0;
if (0 == _LdrGetProcedureAddress)
{
_LdrGetProcedureAddress = getLdrGetProcedureAddress();
if (0 == _LdrGetProcedureAddress)
return 0;
}
_UNICODE_STRING_T<DWORD64> fName = { 0 };
fName.Buffer = (DWORD64)funcName;
fName.Length = (WORD)strlen(funcName);
fName.MaximumLength = fName.Length + 1;
DWORD64 funcRet = 0;
X64Call(_LdrGetProcedureAddress, 4, (DWORD64)hModule, (DWORD64)&fName, (DWORD64)0, (DWORD64)&funcRet);
return funcRet;
}
extern "C" SIZE_T __cdecl VirtualQueryEx64(HANDLE hProcess, DWORD64 lpAddress, MEMORY_BASIC_INFORMATION64* lpBuffer, SIZE_T dwLength)
{
static DWORD64 ntqvm = 0;
if (0 == ntqvm)
{
ntqvm = GetProcAddress64(getNTDLL64(), "NtQueryVirtualMemory");
if (0 == ntqvm)
return 0;
}
DWORD64 ret = 0;
DWORD64 status = X64Call(ntqvm, 6, (DWORD64)hProcess, lpAddress, (DWORD64)0, (DWORD64)lpBuffer, (DWORD64)dwLength, (DWORD64)&ret);
if (STATUS_SUCCESS != status)
SetLastErrorFromX64Call(status);
return (SIZE_T)ret;
}
extern "C" DWORD64 __cdecl VirtualAllocEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
static DWORD64 ntavm = 0;
if (0 == ntavm)
{
ntavm = GetProcAddress64(getNTDLL64(), "NtAllocateVirtualMemory");
if (0 == ntavm)
return 0;
}
DWORD64 tmpAddr = lpAddress;
DWORD64 tmpSize = dwSize;
DWORD64 ret = X64Call(ntavm, 6, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)0, (DWORD64)&tmpSize, (DWORD64)flAllocationType, (DWORD64)flProtect);
if (STATUS_SUCCESS != ret)
{
SetLastErrorFromX64Call(ret);
return FALSE;
}
else
return tmpAddr;
}
extern "C" BOOL __cdecl VirtualFreeEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD dwFreeType)
{
static DWORD64 ntfvm = 0;
if (0 == ntfvm)
{
ntfvm = GetProcAddress64(getNTDLL64(), "NtFreeVirtualMemory");
if (0 == ntfvm)
return 0;
}
DWORD64 tmpAddr = lpAddress;
DWORD64 tmpSize = dwSize;
DWORD64 ret = X64Call(ntfvm, 4, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)dwFreeType);
if (STATUS_SUCCESS != ret)
{
SetLastErrorFromX64Call(ret);
return FALSE;
}
else
return TRUE;
}
extern "C" BOOL __cdecl VirtualProtectEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD* lpflOldProtect)
{
static DWORD64 ntpvm = 0;
if (0 == ntpvm)
{
ntpvm = GetProcAddress64(getNTDLL64(), "NtProtectVirtualMemory");
if (0 == ntpvm)
return 0;
}
DWORD64 tmpAddr = lpAddress;
DWORD64 tmpSize = dwSize;
DWORD64 ret = X64Call(ntpvm, 5, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)flNewProtect, (DWORD64)lpflOldProtect);
if (STATUS_SUCCESS != ret)
{
SetLastErrorFromX64Call(ret);
return FALSE;
}
else
return TRUE;
}
extern "C" BOOL __cdecl ReadProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead)
{
static DWORD64 nrvm = 0;
if (0 == nrvm)
{
nrvm = GetProcAddress64(getNTDLL64(), "NtReadVirtualMemory");
if (0 == nrvm)
return 0;
}
DWORD64 numOfBytes = lpNumberOfBytesRead ? *lpNumberOfBytesRead : 0;
DWORD64 ret = X64Call(nrvm, 5, (DWORD64)hProcess, lpBaseAddress, (DWORD64)lpBuffer, (DWORD64)nSize, (DWORD64)&numOfBytes);
if (STATUS_SUCCESS != ret)
{
SetLastErrorFromX64Call(ret);
return FALSE;
}
else
{
if (lpNumberOfBytesRead)
*lpNumberOfBytesRead = (SIZE_T)numOfBytes;
return TRUE;
}
}
extern "C" BOOL __cdecl WriteProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten)
{
static DWORD64 nrvm = 0;
if (0 == nrvm)
{
nrvm = GetProcAddress64(getNTDLL64(), "NtWriteVirtualMemory");
if (0 == nrvm)
return 0;
}
DWORD64 numOfBytes = lpNumberOfBytesWritten ? *lpNumberOfBytesWritten : 0;
DWORD64 ret = X64Call(nrvm, 5, (DWORD64)hProcess, lpBaseAddress, (DWORD64)lpBuffer, (DWORD64)nSize, (DWORD64)&numOfBytes);
if (STATUS_SUCCESS != ret)
{
SetLastErrorFromX64Call(ret);
return FALSE;
}
else
{
if (lpNumberOfBytesWritten)
*lpNumberOfBytesWritten = (SIZE_T)numOfBytes;
return TRUE;
}
}
extern "C" BOOL __cdecl GetThreadContext64(HANDLE hThread, _CONTEXT64* lpContext)
{
static DWORD64 gtc = 0;
if (0 == gtc)
{
gtc = GetProcAddress64(getNTDLL64(), "NtGetContextThread");
if (0 == gtc)
return 0;
}
DWORD64 ret = X64Call(gtc, 2, (DWORD64)hThread, (DWORD64)lpContext);
if (STATUS_SUCCESS != ret)
{
SetLastErrorFromX64Call(ret);
return FALSE;
}
else
return TRUE;
}
extern "C" BOOL __cdecl SetThreadContext64(HANDLE hThread, _CONTEXT64* lpContext)
{
static DWORD64 stc = 0;
if (0 == stc)
{
stc = GetProcAddress64(getNTDLL64(), "NtSetContextThread");
if (0 == stc)
return 0;
}
DWORD64 ret = X64Call(stc, 2, (DWORD64)hThread, (DWORD64)lpContext);
if (STATUS_SUCCESS != ret)
{
SetLastErrorFromX64Call(ret);
return FALSE;
}
else
return TRUE;
}
enum THREADINFOCLASS;
extern "C" DWORD64 __cdecl NtQueryInformationThread64(HANDLE hThread, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength)
{
static DWORD64 stc = 0;
if (0 == stc)
{
stc = GetProcAddress64(getNTDLL64(), "NtQueryInformationThread");
if (0 == stc)
return 0;
}
DWORD64 ret = X64Call(stc, 5, (DWORD64)hThread, (DWORD64)ThreadInformationClass, (DWORD64)ThreadInformation, (DWORD64)ThreadInformationLength, (DWORD64)ReturnLength);
if (STATUS_SUCCESS != ret)
SetLastErrorFromX64Call(ret);
return ret;
}
extern "C" DWORD64 __cdecl NtSetInformationThread64(HANDLE hThread, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength)
{
static DWORD64 stc = 0;
if (0 == stc)
{
stc = GetProcAddress64(getNTDLL64(), "NtSetInformationThread");
if (0 == stc)
return 0;
}
DWORD64 ret = X64Call(stc, 4, (DWORD64)hThread, (DWORD64)ThreadInformationClass, (DWORD64)ThreadInformation, (DWORD64)ThreadInformationLength);
if (STATUS_SUCCESS != ret)
SetLastErrorFromX64Call(ret);
return ret;
}
typedef LONG KPRIORITY;
typedef struct _THREAD_BASIC_INFORMATION {
NTSTATUS ExitStatus;
DWORD64 TebBaseAddress;
_CLIENT_ID<DWORD64> ClientId;
DWORD64 AffinityMask;
KPRIORITY Priority;
KPRIORITY BasePriority;
} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
extern "C" DWORD64 __declspec(dllexport) __cdecl SetThreadAffinityMask64(HANDLE hThread, DWORD64 mask)
{
THREAD_BASIC_INFORMATION oThreadData;
DWORD64 ret = NtQueryInformationThread64(hThread, (THREADINFOCLASS)0, &oThreadData, sizeof(oThreadData), 0);
if (ret != 0)
return 0;
__declspec(align(8)) DWORD64 mask2 = mask;
ret = NtSetInformationThread64(hThread, (THREADINFOCLASS)4, &mask2, 8);
if (ret != 0)
return 0;
return oThreadData.AffinityMask;
}
extern "C" DWORD __declspec(dllexport) __cdecl SetThreadIdealProcessor64(HANDLE hThread, DWORD mask)
{
__declspec(align(8)) DWORD64 mask2 = mask;
DWORD64 ret = NtSetInformationThread64(hThread, (THREADINFOCLASS)13, &mask2, 4);
if ((ret & 0x80000000) == 0)
return (DWORD)ret;
return -1;
}
int main()
{
HANDLE cTh = GetCurrentThread();
SetThreadIdealProcessor64(cTh, 0);
printf("done.\n");
return 0;
}
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Wow64Ext_ShowSnap.exe]
"GlobalFlag"=dword:00000002
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment