Skip to content

求助关于Unicorn2.1.3使用时发生的未知问题 #2231

@fangzheng1111

Description

@fangzheng1111

在模拟X86指令时发生的,我找不到问题所在,希望您能帮助我,谢谢!
下面是我的代码:
DWORD WINAPI EmulationThreadProc(LPVOID lpParameter)
{
int callvm_count = 0, callapi_count = 0;
int callvm_total = 0, callapi_total = 0;
bool ret = uc_arch_supported(UC_ARCH_X86);
if (!ret)
{
return 0;
}
uc_engine* huc;
uc_err err = uc_open(UC_ARCH_X86, UC_MODE_32, &huc);
if (err != UC_ERR_OK) {
MessageBoxA(hWNd, "初始化Unicorn失败", "", NULL);
return 0;
}
MapProcessMemory(PID, huc);
SetupInitialRegisters(huc, PID);
CallContext ctx;
uc_reg_read(huc, UC_X86_REG_EAX, &ctx.pre_ctx.eax);
uc_reg_read(huc, UC_X86_REG_EBX, &ctx.pre_ctx.ebx);
uc_reg_read(huc, UC_X86_REG_ECX, &ctx.pre_ctx.ecx);
uc_reg_read(huc, UC_X86_REG_EDX, &ctx.pre_ctx.edx);
uc_reg_read(huc, UC_X86_REG_ESI, &ctx.pre_ctx.esi);
uc_reg_read(huc, UC_X86_REG_EDI, &ctx.pre_ctx.edi);
uc_reg_read(huc, UC_X86_REG_EBP, &ctx.pre_ctx.ebp);
//uc_reg_read(huc, UC_X86_REG_ESP, &ctx.pre_ctx.esp);
//uc_reg_read(huc, UC_X86_REG_EFLAGS, &ctx.pre_ctx.EFlags);
uc_hook ret_hook;
uc_hook_add(huc, &ret_hook, UC_HOOK_CODE, (void*)VmRetHook, &ctx, 1, 0);
auto RunSimulation = [&](uint32_t call_addr) {
uc_reg_write(huc, UC_X86_REG_EAX, &ctx.pre_ctx.eax);
uc_reg_write(huc, UC_X86_REG_EBX, &ctx.pre_ctx.ebx);
uc_reg_write(huc, UC_X86_REG_ECX, &ctx.pre_ctx.ecx);
uc_reg_write(huc, UC_X86_REG_EDX, &ctx.pre_ctx.edx);
uc_reg_write(huc, UC_X86_REG_ESI, &ctx.pre_ctx.esi);
uc_reg_write(huc, UC_X86_REG_EDI, &ctx.pre_ctx.edi);
uc_reg_write(huc, UC_X86_REG_EBP, &ctx.pre_ctx.ebp);
//uc_reg_write(huc, UC_X86_REG_ESP, &ctx.pre_ctx.esp);
//uc_reg_write(huc, UC_X86_REG_EFLAGS, &ctx.pre_ctx.EFlags);
ctx.call_addr = call_addr;
uc_reg_write(huc, UC_X86_REG_EIP, &call_addr);
err = uc_emu_start(huc, call_addr, 0, 0, 0);
if (err != UC_ERR_OK) {
CString log;
const char* err_str = uc_strerror(err);
uint32_t current_eip;
uc_reg_read(huc, UC_X86_REG_EIP, &current_eip);
uint32_t esp_value;
uc_reg_read(huc, UC_X86_REG_ESP, &esp_value);
log.Format(_T("模拟失败 @ 0x%08X:\n")
_T(" 错误: %hs (代码: 0x%X)\n")
_T(" 当前EIP: 0x%08X\n")
_T(" ESP: 0x%08X\n"),
call_addr,
err_str ? err_str : "未知错误",
err,
current_eip,
esp_value);
OutputDebugString(log);
}
};
callvm_total = callvm.size();
for (uint32_t call_addr : callvm) {
RunSimulation(call_addr);
callvm_count++;
}
callapi_total = callapi.size();
for (uint32_t call_addr : callapi) {
RunSimulation(call_addr);
callapi_count++;
}
CString log;
log.Format(_T("处理完成: callvm=%d/%d, callapi=%d/%d, 丢失=%d"),
callvm_count, callvm_total,
callapi_count, callapi_total,
(callvm_total + callapi_total) - (callvm_count + callapi_count));
AddLogEntry(log);
uc_hook_del(huc, ret_hook);
uc_close(huc);
MessageBoxA(hWNd,"分析完成","",NULL);
return 0;
}
void SetupInitialRegisters(uc_engine* uc, DWORD pid) {
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProcess) {
return;
}
HANDLE hThread = GetMainThreadHandle(pid);
if (!hThread) {
CloseHandle(hProcess);
return;
}
CONTEXT ctx = GetThreadContext(hThread);
static _NtQueryInformationThread NtQueryInformationThread = NULL;
static bool initialized = false;
if (!initialized) {
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
if (ntdll) {
NtQueryInformationThread = (_NtQueryInformationThread)GetProcAddress(ntdll, "NtQueryInformationThread");
}
initialized = true;
}
THREAD_BASIC_INFORMATION tbi;
ULONG len;
NTSTATUS status = NtQueryInformationThread(
hThread,
(THREADINFOCLASS)0,
&tbi,
sizeof(tbi),
&len
);
//uc_reg_write(uc, UC_X86_REG_FS_BASE, &(uint32_t)tbi.TebBaseAddress); //Whether it is needed ?
uc_reg_write(uc, UC_X86_REG_EAX, &ctx.Eax);
uc_reg_write(uc, UC_X86_REG_EBX, &ctx.Ebx);
uc_reg_write(uc, UC_X86_REG_ECX, &ctx.Ecx);
uc_reg_write(uc, UC_X86_REG_EDX, &ctx.Edx);
uc_reg_write(uc, UC_X86_REG_ESI, &ctx.Esi);
uc_reg_write(uc, UC_X86_REG_EDI, &ctx.Edi);
uc_reg_write(uc, UC_X86_REG_EBP, &ctx.Ebp);
uc_reg_write(uc, UC_X86_REG_ESP, &ctx.Esp);
uint32_t cs = ctx.SegCs;
uint32_t ds = ctx.SegDs;
uint32_t es = ctx.SegEs;
uint32_t fs = ctx.SegFs;
uint32_t gs = ctx.SegGs;
uint32_t ss = ctx.SegSs;
uc_reg_write(uc, UC_X86_REG_CS, &cs);
uc_reg_write(uc, UC_X86_REG_DS, &ds);
uc_reg_write(uc, UC_X86_REG_ES, &es);
uc_reg_write(uc, UC_X86_REG_FS, &fs);
uc_reg_write(uc, UC_X86_REG_GS, &gs);
uc_reg_write(uc, UC_X86_REG_SS, &ss);
uc_reg_write(uc, UC_X86_REG_EFLAGS, &ctx.EFlags);
uc_reg_write(uc, UC_X86_REG_DR0, &ctx.Dr0);
uc_reg_write(uc, UC_X86_REG_DR1, &ctx.Dr1);
uc_reg_write(uc, UC_X86_REG_DR0, &ctx.Dr2);
uc_reg_write(uc, UC_X86_REG_DR1, &ctx.Dr3);
uc_reg_write(uc, UC_X86_REG_DR0, &ctx.Dr6);
uc_reg_write(uc, UC_X86_REG_DR1, &ctx.Dr7);
// 1. FPU控制和状态寄存器
uc_reg_write(uc, UC_X86_REG_FPCW, &ctx.FloatSave.ControlWord);
uc_reg_write(uc, UC_X86_REG_FPSW, &ctx.FloatSave.StatusWord);
uc_reg_write(uc, UC_X86_REG_FPTAG, &ctx.FloatSave.TagWord);
// 2. 浮点错误相关寄存器
uc_reg_write(uc, UC_X86_REG_FIP, &ctx.FloatSave.ErrorOffset);
uc_reg_write(uc, UC_X86_REG_FCS, &ctx.FloatSave.ErrorSelector);
uc_reg_write(uc, UC_X86_REG_FDP, &ctx.FloatSave.DataOffset);
uc_reg_write(uc, UC_X86_REG_FDS, &ctx.FloatSave.DataSelector);
// 3. 浮点寄存器堆(ST0-ST7)
// 每个寄存器在RegisterArea中占10字节(80位)
if (sizeof(ctx.FloatSave.RegisterArea) == SIZE_OF_80387_REGISTERS) {
uc_reg_write(uc, UC_X86_REG_ST0, &ctx.FloatSave.RegisterArea[0]);
uc_reg_write(uc, UC_X86_REG_ST1, &ctx.FloatSave.RegisterArea[10]);
uc_reg_write(uc, UC_X86_REG_ST2, &ctx.FloatSave.RegisterArea[20]);
uc_reg_write(uc, UC_X86_REG_ST3, &ctx.FloatSave.RegisterArea[30]);
uc_reg_write(uc, UC_X86_REG_ST4, &ctx.FloatSave.RegisterArea[40]);
uc_reg_write(uc, UC_X86_REG_ST5, &ctx.FloatSave.RegisterArea[50]);
uc_reg_write(uc, UC_X86_REG_ST6, &ctx.FloatSave.RegisterArea[60]);
uc_reg_write(uc, UC_X86_REG_ST7, &ctx.FloatSave.RegisterArea[70]);
OutputDebugString(_T("浮点数寄存器堆初始化完成\n"));
}
//const uint32_t STACK_SIZE = 0x50000; // 128KB保守堆栈大小
//uint32_t stack_base = 0x2000000; // 栈底地址(4字节对齐)
//uc_err stack_err = uc_mem_map(uc, stack_base, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE);
//uint32_t esp = stack_base + STACK_SIZE;
//uc_reg_write(uc, UC_X86_REG_ESP, &esp);
CloseHandle(hThread);
CloseHandle(hProcess);
}
void MapProcessMemory(DWORD pid, uc_engine* uc )
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);
if (!hProcess) return;
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
const DWORD PAGE_SIZE = sysInfo.dwPageSize;
const ULONG_PTR PAGE_MASK = ~(ULONG_PTR)(PAGE_SIZE - 1);
MEMORY_BASIC_INFORMATION mbi;
ULONG_PTR address = 0;
const uint32_t NULL_AREA_START = 0x00000000;
const uint32_t NULL_AREA_SIZE = 0x10000; // 64KB
if (uc_mem_map(uc, NULL_AREA_START, NULL_AREA_SIZE, UC_PROT_NONE) == UC_ERR_OK) {
std::vector<uint8_t> zeros(NULL_AREA_SIZE, 0);
uc_mem_write(uc, NULL_AREA_START, zeros.data(), zeros.size());
}
while (VirtualQueryEx(hProcess, (LPCVOID)address, &mbi, sizeof(mbi))) {
ULONG_PTR base = (ULONG_PTR)mbi.BaseAddress;
ULONG_PTR regionStart = base & PAGE_MASK;
ULONG_PTR regionEnd = (base + mbi.RegionSize + PAGE_SIZE - 1) & PAGE_MASK;
size_t regionSize = regionEnd - regionStart;
if (regionSize == 0 ||
mbi.State != MEM_COMMIT ||
(mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS))) {
address = regionEnd;
continue;
}
if (uc_mem_map(uc, regionStart, regionSize, UC_PROT_ALL) == UC_ERR_OK) {
const size_t BLOCK_SIZE = 4096;
std::vector<uint8_t> buffer(BLOCK_SIZE);
for (ULONG_PTR offset = 0; offset < regionSize; offset += BLOCK_SIZE) {
size_t toRead = min(BLOCK_SIZE, regionSize - offset);
if (ReadProcessMemory(hProcess, (LPCVOID)(regionStart + offset),
buffer.data(), toRead, NULL)) {
uc_mem_write(uc, regionStart + offset, buffer.data(), toRead);
}
}
}
address = regionEnd;
}
CloseHandle(hProcess);
}
我直接映射的整个进程空间,寄存器相关是直接在线程上下文中获取的,我不知道是否是模拟环境构建错误,还是我落下了重要的未设置的重点。
下面是vs输出的错误,它会一直发生。
模拟失败 @ 0x004401F2:
错误: Unhandled CPU exception (UC_ERR_EXCEPTION) (代码: 0x15)
当前EIP: 0x00AE0BE3
ESP: 0x0019F83C
模拟失败 @ 0x004AB76D:
错误: Read from non-readable memory (UC_ERR_READ_PROT) (代码: 0xD)
当前EIP: 0x005D9274
ESP: 0x0019EAB8
模拟失败 @ 0x004B28F5:
错误: Invalid memory write (UC_ERR_WRITE_UNMAPPED) (代码: 0x7)
当前EIP: 0x00998342
ESP: 0x0019E6CC
模拟失败 @ 0x004ABA5A:
错误: Read from non-readable memory (UC_ERR_READ_PROT) (代码: 0xD)
当前EIP: 0x005D9274
ESP: 0x0019D1A4
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
0x004330DE 处(位于 AT.exe 中)引发的异常: 0xC0000005: 写入位置 0x08A21000 时发生访问冲突。
................
请帮助我看一看到底是什么原因,谢谢!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions