也许我很愚蠢,但我真的没有在他们的文档中看到任何内容。说我模拟这个代码
mov eax, 1
mov ecx, 2
然后我可以得到这样的结果:
int rr;
uc_reg_read(uc, UC_X86_REG_ECX, &rr);
现在我想知道 - 当我从一个未定义的寄存器中读取时会发生什么,比如 ESI?
uc_reg_read(uc, UC_X86_REG_ESI, &rr);
答案是 rr == 0。但是我怎么能检测到这个寄存器是未定义的,而不是“0”呢?
也许我很愚蠢,但我真的没有在他们的文档中看到任何内容。说我模拟这个代码
mov eax, 1
mov ecx, 2
然后我可以得到这样的结果:
int rr;
uc_reg_read(uc, UC_X86_REG_ECX, &rr);
现在我想知道 - 当我从一个未定义的寄存器中读取时会发生什么,比如 ESI?
uc_reg_read(uc, UC_X86_REG_ESI, &rr);
答案是 rr == 0。但是我怎么能检测到这个寄存器是未定义的,而不是“0”呢?
模拟器需要你的输入来模拟如果你没有定义一些你显然会得到它初始化的东西
显然独角兽开始为所有寄存器初始化为 0 似乎
src 使用给定的 api 读取所有寄存器
:\>cat testumu.cpp
#include "unicorn.h"
#pragma comment(lib,"unicorn.lib")
#define REG_NUMS 9
void main (void) {
uc_engine *uc;
int regs[REG_NUMS] = {
UC_X86_REG_EAX,UC_X86_REG_EBX,UC_X86_REG_ECX,
UC_X86_REG_EDX,UC_X86_REG_EBP,UC_X86_REG_ESP,
UC_X86_REG_ESI,UC_X86_REG_EDI,UC_X86_REG_EIP
};
int bugs[REG_NUMS] = {1,2,3,4,5,6,7,8,9};
void *vals[REG_NUMS];
for(int i =0; i<REG_NUMS;i++) {
vals[i] = &bugs[i];
}
printf("values before reading\n\n");
for(int i =0 ; i< REG_NUMS; i++) {
printf("%x\t%x\n" , regs[i],*(int *)vals[i]);
}
if((uc_open(UC_ARCH_X86, UC_MODE_32, &uc)) == UC_ERR_OK) {
uc_reg_read_batch(uc,regs,vals,9);
}
printf("values after reading\n\n");
for(int i =0 ; i< REG_NUMS; i++) {
printf("%x\t%x\n" , regs[i],*(int *)vals[i]);
}
}
编译并链接到 x86 的 vc2017 社区 cmd 提示
:\>cl /nologo /Zi /W4 /analyze /Ox testumu.cpp /link /release
testumu.cpp
:\>
编译的可执行文件的结果
:\>testumu.exe
values before reading
13 1
15 2
16 3
18 4
14 5
1e 6
1d 7
17 8
1a 9
values after reading
13 0
15 0
16 0
18 0
14 0
1e 0
1d 0
17 0
1a 0
:\>
Unicorn 只支持寄存器中的具体值。您可以通过使用两组魔法值进行两次运行来绕过这个问题。
但是你真正想要的是一个符号执行框架,比如angr。执行后寄存器可能未定义,甚至包含像 old_ebx*2+1 这样的表达式树。