这是维基上对ASLR的解释. 这里还要说明一下, 维基中说ASLR仅适用于动态链接库和可执行文件.
这样说是不严谨的. 因为可执行文件中如果没有重定位表, 也一样是不适用的.
咱们的cpudbg已经支持禁用ASLR功能了. 如图:
这个是通过 PE 结构中的 ntHeaders.OptionalHeader.DllCharacteristics 来实现禁用的.
禁用后另存为一份文件. 一次修改,终生有效.
具体的可以看之前的视频.
但有的时候, 目标程序有加外壳, 现在大多加密壳都有自校验, 如果直接修改, 运行就会报错.
那有没有什么办法, 不修改PE文件, 又同时能禁用ASLR呢? 答案是当然有.
刚开始我又尝试和GPT摆会龙门阵. GPT 告诉我很多方法, 其中包括但不限于:
1. 编译时通过IDE设置禁用
2. 通过注册表禁用
3. WINDBG命令 .disable_aslr
4. GDB命令 set disable-randomization on
GPT说的这些都不是我想要的, 我想要的是能一次性, 用完就又恢复的,同时又不修改自身,也不修改系统. 更不会使用三方库或调试器.
和GPT又扯了一会, 它又告诉我用 SetProcessMitigationPolicy 函数.
[C] 纯文本查看 复制代码 BOOL SetProcessMitigationPolicy(
PROCESS_MITIGATION_POLICY MitigationPolicy,
PVOID lpBuffer,
SIZE_T dwLength
);
看了下这个函数都没有进程句柄,或PID. 大概率是修改自身的. 还是没卵用...
于是又和GPT扯了好久 好久. 然后它也开始天马行空的回答了.
它告诉我在PEB中有一个标志位(不存在), 那个标志位就是用来控制 ASLR开关的.
下面是GPT给的代码, 其中 flags 就是不存在的.
[C] 纯文本查看 复制代码 #include <windows.h>
#include <stdio.h>
BOOL DisableASLRAndLaunch(LPCSTR applicationName) {
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Create the process in a suspended state
if (!CreateProcessA(applicationName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED | DEBUG_PROCESS, NULL, NULL, &si, &pi)) {
printf("CreateProcess failed (%d).\n", GetLastError());
return FALSE;
}
// Disable ASLR by modifying the process's PEB (Process Environment Block)
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(pi.hThread, &ctx)) {
printf("GetThreadContext failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
// Adjust the PEB flags to disable ASLR
PEB* peb = (PEB*)ctx.Rdx; // On x64, PEB address is in Rdx
// On x86, use ctx.Ebx to get the PEB address instead
// Read and modify the PEB flags to disable ASLR
DWORD oldProtect;
if (!VirtualProtectEx(pi.hProcess, &peb->Flags, sizeof(peb->Flags), PAGE_READWRITE, &oldProtect)) {
printf("VirtualProtectEx failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
DWORD flags;
if (!ReadProcessMemory(pi.hProcess, &peb->Flags, &flags, sizeof(flags), NULL)) {
printf("ReadProcessMemory failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
flags &= ~0x4; // Clear the ASLR flag (0x4)
if (!WriteProcessMemory(pi.hProcess, &peb->Flags, &flags, sizeof(flags), NULL)) {
printf("WriteProcessMemory failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
if (!VirtualProtectEx(pi.hProcess, &peb->Flags, sizeof(peb->Flags), oldProtect, &oldProtect)) {
printf("VirtualProtectEx restore failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
// Resume the process
if (ResumeThread(pi.hThread) == -1) {
printf("ResumeThread failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
// Wait for the process to exit
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return TRUE;
}
int main() {
if (DisableASLRAndLaunch("C:\\Path\\To\\Your\\Application.exe")) {
printf("ASLR disabled and application launched successfully.\n");
} else {
printf("Failed to disable ASLR and launch application.\n");
}
return 0;
}
聊到最后, GPT 终于说了一个看起来有亿点点靠谱的回答.
代码如下:
[C] 纯文本查看 复制代码
#include <windows.h>
#include <stdio.h>
BOOL DisableASLRAndLaunch(LPCSTR applicationName) {
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Create the process in a suspended state
if (!CreateProcessA(applicationName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
printf("CreateProcess failed (%d).\n", GetLastError());
return FALSE;
}
// Get the PEB address
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(pi.hThread, &ctx)) {
printf("GetThreadContext failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
#ifdef _WIN64
PEB* peb = (PEB*)ctx.Rdx; // On x64, PEB address is in Rdx
#else
PEB* peb = (PEB*)ctx.Ebx; // On x86, PEB address is in Ebx
#endif
// Adjust the PEB flags to disable ASLR
DWORD oldProtect;
if (!VirtualProtectEx(pi.hProcess, peb, sizeof(PEB), PAGE_READWRITE, &oldProtect)) {
printf("VirtualProtectEx failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
PEB pebCopy;
if (!ReadProcessMemory(pi.hProcess, peb, &pebCopy, sizeof(pebCopy), NULL)) {
printf("ReadProcessMemory failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
pebCopy.ImageBaseAddress = (PVOID)0x00400000; // Set ImageBaseAddress to disable ASLR
if (!WriteProcessMemory(pi.hProcess, peb, &pebCopy, sizeof(pebCopy), NULL)) {
printf("WriteProcessMemory failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
if (!VirtualProtectEx(pi.hProcess, peb, sizeof(PEB), oldProtect, &oldProtect)) {
printf("VirtualProtectEx restore failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
// Resume the process
if (ResumeThread(pi.hThread) == -1) {
printf("ResumeThread failed (%d).\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
return FALSE;
}
// Wait for the process to exit
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return TRUE;
}
int main() {
if (DisableASLRAndLaunch("C:\\Path\\To\\Your\\Application.exe")) {
printf("ASLR disabled and application launched successfully.\n");
} else {
printf("Failed to disable ASLR and launch application.\n");
}
return 0;
}
GPT是直接修改PEB中的基址.看起来好像没问题,先编译个GPT的代码来加载一个支持ASLR的程序试试.
运行后,直接报错了...
GPT中的方法,是通过系统第一次中断,从CONTEXT中拿到PEB, 然后直接修改PEB中的imagebase.
将原先的基址,强制修改成 0x00400000. 这看着好像没有问题.
但由于系统第一次中断时, 时机已经晚了. 原始的ASLR基址已经被系统分配了.
而转到 0x00400000 还是未分配状态. 因此报错是正常的.
那这样还有办法动态禁用ASLR吗? 当然答案是有的. 只是会麻烦些...
(群里有朋友强烈建议先更新调试器的核心功能. 其它附属功能等调试器稳定后再更新.这个禁用ASLR的功能就等以后出正式版之后再更新吧...)
--------------------------------------------------------------------
to be continued... |