在加壳软件中,ntdll.dll里的有些API会被加壳软件hook,导致我们在做补丁无法正常执行
如:有的程序会hook NtGetContextThread和NtSetContextThread,导致无法下硬件断点,也有的会hook NtProtectVirtualMemory,无法修改内存属性,就不能修改汇编代码等……
Nt或Zw开头的函数执行的代码是一样的,他们所指向的函数地址都是同一个,具体有什么不同,请自行搜索查看,我这里使用Nt函数进行编写。
char dllPath[MAX_PATH];
GetSystemDirectoryA(dllPath, MAX_PATH);
strcat_s(dllPath, MAX_PATH,
"\\ntdll.dll"
);
/
/
拼接系统目录ntdll.dll路径
HANDLE hFile
=
CreateFileA(dllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if
(hFile
=
=
INVALID_HANDLE_VALUE)
return
functionAddress;
char dllPath[MAX_PATH];
GetSystemDirectoryA(dllPath, MAX_PATH);
strcat_s(dllPath, MAX_PATH,
"\\ntdll.dll"
);
/
/
拼接系统目录ntdll.dll路径
HANDLE hFile
=
CreateFileA(dllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if
(hFile
=
=
INVALID_HANDLE_VALUE)
return
functionAddress;
/
/
把ntdll读入进内存
DWORD dwRead
=
0
;
DWORD dwSize
=
GetFileSize(hFile, &dwRead);
BYTE
*
pBuff
=
new BYTE[dwSize];
RtlZeroMemory(pBuff, sizeof(pBuff));
ReadFile(hFile, pBuff, dwSize, &dwRead, NULL);
/
/
把ntdll读入进内存
DWORD dwRead
=
0
;
DWORD dwSize
=
GetFileSize(hFile, &dwRead);
BYTE
*
pBuff
=
new BYTE[dwSize];
RtlZeroMemory(pBuff, sizeof(pBuff));
ReadFile(hFile, pBuff, dwSize, &dwRead, NULL);
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)pBuff;
PIMAGE_NT_HEADERS64 pNtHeader
=
(PIMAGE_NT_HEADERS64)(pDosHeader
-
>e_lfanew
+
((ULONG_PTR)pDosHeader));
PIMAGE_SECTION_HEADER pSectionHeader
=
(PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader))
+
sizeof(IMAGE_NT_HEADERS64));
PIMAGE_NT_HEADERS32 pNtHeader
=
(PIMAGE_NT_HEADERS32)(pDosHeader
-
>e_lfanew
+
((ULONG_PTR)pDosHeader));
PIMAGE_SECTION_HEADER pSectionHeader
=
(PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader))
+
sizeof(IMAGE_NT_HEADERS32));
ULONG_PTR foaAddress
=
0
;
/
/
Nt函数地址
-
ntdll基址
=
rva
ULONG_PTR rva
=
apiAddress
-
(ULONG_PTR)dllHandle;
for
(WORD i
=
0
; i < pNtHeader
-
>FileHeader.NumberOfSections;
+
+
i)
{
if
(rva > pSectionHeader[i].VirtualAddress && rva < pSectionHeader[i].VirtualAddress
+
pSectionHeader[i].SizeOfRawData)
{
/
/
找到foa地址
foaAddress
=
rva
-
pSectionHeader[i].VirtualAddress
+
pSectionHeader[i].PointerToRawData;
break
;
}
}
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)pBuff;
PIMAGE_NT_HEADERS64 pNtHeader
=
(PIMAGE_NT_HEADERS64)(pDosHeader
-
>e_lfanew
+
((ULONG_PTR)pDosHeader));
PIMAGE_SECTION_HEADER pSectionHeader
=
(PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader))
+
sizeof(IMAGE_NT_HEADERS64));
PIMAGE_NT_HEADERS32 pNtHeader
=
(PIMAGE_NT_HEADERS32)(pDosHeader
-
>e_lfanew
+
((ULONG_PTR)pDosHeader));
PIMAGE_SECTION_HEADER pSectionHeader
=
(PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader))
+
sizeof(IMAGE_NT_HEADERS32));
ULONG_PTR foaAddress
=
0
;
/
/
Nt函数地址
-
ntdll基址
=
rva
ULONG_PTR rva
=
apiAddress
-
(ULONG_PTR)dllHandle;
for
(WORD i
=
0
; i < pNtHeader
-
>FileHeader.NumberOfSections;
+
+
i)
{
if
(rva > pSectionHeader[i].VirtualAddress && rva < pSectionHeader[i].VirtualAddress
+
pSectionHeader[i].SizeOfRawData)
{
/
/
找到foa地址
foaAddress
=
rva
-
pSectionHeader[i].VirtualAddress
+
pSectionHeader[i].PointerToRawData;
break
;
}
}
/
/
opcode读取
int
opcodeOffset
=
0
;
while
(true)
{
/
/
x64位opcode读取
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
if
(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset)
=
=
0xC3
)
/
/
遇到ret指令结束
{
/
/
C3 ret
/
/
CD
2E
int
2E
/
/
C3 ret
/
/
遇到C3后还要追加
int
2E
ret指令
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
CD
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
2E
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
C3
break
;
}
+
+
opcodeOffset;
}
while
(true)
{
/
/
x86位opcode读取
if
(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset)
=
=
0xC2
&& opcodeOffset >
10
)
/
/
遇到ret指令结束
{
/
/
C2
2000
ret
20
/
/
遇到C2后还要追加返回值opcode
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
/
/
C2
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
20
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
00
break
;
}
/
/
x86 opcode在
8
、
9
位时foa值与va值不同,需要特殊处理
else
if
(opcodeOffset
=
=
8
|| opcodeOffset
=
=
9
)
{
functionBytes.push_back(
*
(BYTE
*
)(apiAddress
+
opcodeOffset));
}
else
{
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
}
+
+
opcodeOffset;
}
/
/
opcode读取
int
opcodeOffset
=
0
;
while
(true)
{
/
/
x64位opcode读取
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
if
(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset)
=
=
0xC3
)
/
/
遇到ret指令结束
{
/
/
C3 ret
/
/
CD
2E
int
2E
/
/
C3 ret
/
/
遇到C3后还要追加
int
2E
ret指令
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
CD
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
2E
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
C3
break
;
}
+
+
opcodeOffset;
}
while
(true)
{
/
/
x86位opcode读取
if
(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset)
=
=
0xC2
&& opcodeOffset >
10
)
/
/
遇到ret指令结束
{
/
/
C2
2000
ret
20
/
/
遇到C2后还要追加返回值opcode
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
/
/
C2
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
20
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
00
break
;
}
/
/
x86 opcode在
8
、
9
位时foa值与va值不同,需要特殊处理
else
if
(opcodeOffset
=
=
8
|| opcodeOffset
=
=
9
)
{
functionBytes.push_back(
*
(BYTE
*
)(apiAddress
+
opcodeOffset));
}
else
{
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
}
+
+
opcodeOffset;
}
/
/
申请堆空间执行汇编代码
int
sizeCustomFunction
=
functionBytes.size();
functionAddress
=
(BYTE
*
)VirtualAlloc(
0
, sizeCustomFunction, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
for
(
int
j
=
0
; j < sizeCustomFunction; j
+
+
)
{
/
/
写入opcode到新内存,执行汇编代码
*
(functionAddress
+
j)
=
functionBytes[j];
}
/
/
申请堆空间执行汇编代码
int
sizeCustomFunction
=
functionBytes.size();
functionAddress
=
(BYTE
*
)VirtualAlloc(
0
, sizeCustomFunction, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
for
(
int
j
=
0
; j < sizeCustomFunction; j
+
+
)
{
/
/
写入opcode到新内存,执行汇编代码
*
(functionAddress
+
j)
=
functionBytes[j];
}
/
/
NtGetContextThread
typedef
BOOL
(NTAPI
*
PNtGetContextThread)(HANDLE hThread, LPCONTEXT lpContext);
PNtGetContextThread pZwGetContextThread;
BOOL
MyNtGetContextThread(HANDLE hThread, LPCONTEXT lpContext)
{
pZwGetContextThread
=
(PNtGetContextThread)CustomNtFunction(
"NtGetContextThread"
);
return
pZwGetContextThread(hThread, lpContext);
}
/
/
NtSetContextThread
typedef
BOOL
(CALLBACK
*
PNtSetContextThread)(HANDLE hThread, LPCONTEXT lpContext);
PNtSetContextThread pZwSetContextThread;
BOOL
MyNtSetContextThread(HANDLE hThread, LPCONTEXT lpContext)
{
pZwGetContextThread
=
(PNtSetContextThread)CustomNtFunction(
"NtSetContextThread"
);
return
pZwGetContextThread(hThread, lpContext);
}
/
/
NtProtectVirtualMemory
typedef
BOOL
(NTAPI
*
PNtProtectVirtualMemory)(HANDLE hProcess, PVOID
*
lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect);
PNtProtectVirtualMemory pNtProtectVirtualMemory;
BOOL
MyNtProtectVirtualMemory(HANDLE hProcess, PVOID
*
lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect)
{
/
/
将函数名转换为地址并执行
pNtProtectVirtualMemory
=
(PNtProtectVirtualMemory)CustomNtFunction(
"NtProtectVirtualMemory"
);
return
pNtProtectVirtualMemory(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect);
}
/
/
NtGetContextThread
typedef
BOOL
(NTAPI
*
PNtGetContextThread)(HANDLE hThread, LPCONTEXT lpContext);
PNtGetContextThread pZwGetContextThread;
BOOL
MyNtGetContextThread(HANDLE hThread, LPCONTEXT lpContext)
{
pZwGetContextThread
=
(PNtGetContextThread)CustomNtFunction(
"NtGetContextThread"
);
return
pZwGetContextThread(hThread, lpContext);
}
/
/
NtSetContextThread
typedef
BOOL
(CALLBACK
*
PNtSetContextThread)(HANDLE hThread, LPCONTEXT lpContext);
PNtSetContextThread pZwSetContextThread;
BOOL
MyNtSetContextThread(HANDLE hThread, LPCONTEXT lpContext)
{
pZwGetContextThread
=
(PNtSetContextThread)CustomNtFunction(
"NtSetContextThread"
);
return
pZwGetContextThread(hThread, lpContext);
}
/
/
NtProtectVirtualMemory
typedef
BOOL
(NTAPI
*
PNtProtectVirtualMemory)(HANDLE hProcess, PVOID
*
lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect);
PNtProtectVirtualMemory pNtProtectVirtualMemory;
BOOL
MyNtProtectVirtualMemory(HANDLE hProcess, PVOID
*
lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect)
{
/
/
将函数名转换为地址并执行
pNtProtectVirtualMemory
=
(PNtProtectVirtualMemory)CustomNtFunction(
"NtProtectVirtualMemory"
);
return
pNtProtectVirtualMemory(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect);
}
BYTE
*
CustomNtFunction(const char
*
functionName)
{
std::vector<BYTE> functionBytes;
BYTE
*
functionAddress
=
NULL;
char dllPath[MAX_PATH];
GetSystemDirectoryA(dllPath, MAX_PATH);
strcat_s(dllPath, MAX_PATH,
"\\ntdll.dll"
);
/
/
拼接系统目录ntdll.dll路径
HANDLE hFile
=
CreateFileA(dllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if
(hFile
=
=
INVALID_HANDLE_VALUE)
return
functionAddress;
HMODULE dllHandle
=
LoadLibraryA(dllPath);
ULONG_PTR apiAddress
=
(ULONG_PTR)GetProcAddress(dllHandle, functionName);
/
/
把ntdll读入进内存
DWORD dwRead
=
0
;
DWORD dwSize
=
GetFileSize(hFile, &dwRead);
BYTE
*
pBuff
=
new BYTE[dwSize];
RtlZeroMemory(pBuff, sizeof(pBuff));
ReadFile(hFile, pBuff, dwSize, &dwRead, NULL);
/
/
通过apiAddress地址获取函数的foa地址
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)pBuff;
PIMAGE_NT_HEADERS64 pNtHeader
=
(PIMAGE_NT_HEADERS64)(pDosHeader
-
>e_lfanew
+
((ULONG_PTR)pDosHeader));
PIMAGE_SECTION_HEADER pSectionHeader
=
(PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader))
+
sizeof(IMAGE_NT_HEADERS64));
PIMAGE_NT_HEADERS32 pNtHeader
=
(PIMAGE_NT_HEADERS32)(pDosHeader
-
>e_lfanew
+
((ULONG_PTR)pDosHeader));
PIMAGE_SECTION_HEADER pSectionHeader
=
(PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader))
+
sizeof(IMAGE_NT_HEADERS32));
ULONG_PTR foaAddress
=
0
;
/
/
Nt函数地址
-
ntdll基址
=
rva
ULONG_PTR rva
=
apiAddress
-
(ULONG_PTR)dllHandle;
for
(WORD i
=
0
; i < pNtHeader
-
>FileHeader.NumberOfSections;
+
+
i)
{
if
(rva > pSectionHeader[i].VirtualAddress && rva < pSectionHeader[i].VirtualAddress
+
pSectionHeader[i].SizeOfRawData)
{
/
/
找到foa地址
foaAddress
=
rva
-
pSectionHeader[i].VirtualAddress
+
pSectionHeader[i].PointerToRawData;
break
;
}
}
/
/
opcode读取
int
opcodeOffset
=
0
;
while
(true)
{
/
/
x64位opcode读取
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
if
(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset)
=
=
0xC3
)
/
/
遇到ret指令结束
{
/
/
C3 ret
/
/
CD
2E
int
2E
/
/
C3 ret
/
/
遇到C3后还要追加
int
2E
ret指令
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
CD
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
2E
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
C3
break
;
}
+
+
opcodeOffset;
}
while
(true)
{
/
/
x86位opcode读取
if
(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset)
=
=
0xC2
&& opcodeOffset >
10
)
/
/
遇到ret指令结束
{
/
/
C2
2000
ret
20
/
/
遇到C2后还要追加返回值opcode
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
/
/
C2
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
20
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
+
+
opcodeOffset));
/
/
00
break
;
}
/
/
x86 opcode在
8
、
9
位时foa值与va值不同,需要特殊处理
else
if
(opcodeOffset
=
=
8
|| opcodeOffset
=
=
9
)
{
functionBytes.push_back(
*
(BYTE
*
)(apiAddress
+
opcodeOffset));
}
else
{
functionBytes.push_back(
*
(BYTE
*
)(pBuff
+
foaAddress
+
opcodeOffset));
}
+
+
opcodeOffset;
}
/
/
申请堆空间执行汇编代码
int
sizeCustomFunction
=
functionBytes.size();
functionAddress
=
(BYTE
*
)VirtualAlloc(
0
, sizeCustomFunction, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
for
(
int
j
=
0
; j < sizeCustomFunction; j
+
+
)
{
/
/
写入opcode到新内存,执行汇编代码
*
(functionAddress
+
j)
=
functionBytes[j];
}
delete[] pBuff; pBuff
=
NULL;
CloseHandle(hFile);
return
functionAddress;
}
/
/
NtProtectVirtualMemory
typedef
BOOL
(NTAPI
*
PNtProtectVirtualMemory)(HANDLE hProcess, PVOID
*
lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect);
PNtProtectVirtualMemory pNtProtectVirtualMemory;
BOOL
MyNtProtectVirtualMemory(HANDLE hProcess, PVOID
*
lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect)
{
/
/
将函数名转换为地址并执行
pNtProtectVirtualMemory
=
(PNtProtectVirtualMemory)CustomNtFunction(
"NtProtectVirtualMemory"
);
return
pNtProtectVirtualMemory(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect);
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 21小时前
被wtujoxk编辑
,原因: