Unicorn引擎教程(二)
第一部分请查看:Unicorn引擎教程(一)
任务2
分析一下代码:
shellcode ="\xe8\xff\xff\xff\xff\xc0\x5d\x6a\x05\x5b\x29\xdd\x83\xc5\x4e\x89\xe9\x6a\x02\x03\x0c\x24\x5b\x31\xd2\x66\xba\x12\x00\x8b\x39\xc1\xe7\x10\xc1\xef\x10\x81\xe9\xfe\xff\xff\xff\x8b\x45\x00\xc1\xe0\x10\xc1\xe8\x10\x89\xc3\x09\xfb\x21\xf8\xf7\xd0\x21\xd8\x66\x89\x45\x00\x83\xc5\x02\x4a\x85\xd2\x0f\x85\xcf\xff\xff\xff\xec\x37\x75\x5d\x7a\x05\x28\xed\x24\xed\x24\xed\x0b\x88\x7f\xeb\x50\x98\x38\xf9\x5c\x96\x2b\x96\x70\xfe\xc6\xff\xc6\xff\x9f\x32\x1f\x58\x1e\x00\xd3\x80"
如你所见,代码被混淆了(命令disasm是pwntools的一部分):
a@x:~/Desktop/unicorn_engine_lessons$ disasm e8ffffffffc05d6a055b29dd83c54e89e96a02030c245b31d266ba12008b39c1e710c1ef1081e9feffffff8b4500c1e010c1e81089c309fb21f8f7d021d86689450083c5024a85d20f85cfffffffec37755d7a0528ed24ed24ed0b887feb509838f95c962b9670fec6ffc6ff9f321f581e00d3800: e8 ff ff ff ff call 0x45: c0 5d 6a 05 rcr BYTE PTR [ebp+0x6a], 0x59: 5b pop ebxa: 29 dd sub ebp, ebxc: 83 c5 4e add ebp, 0x4ef: 89 e9 mov ecx, ebp11: 6a 02 push 0x213: 03 0c 24 add ecx, DWORD PTR [esp]16: 5b pop ebx17: 31 d2 xor edx, edx19: 66 ba 12 00 mov dx, 0x121d: 8b 39 mov edi, DWORD PTR [ecx]1f: c1 e7 10 shl edi, 0x1022: c1 ef 10 shr edi, 0x1025: 81 e9 fe ff ff ff sub ecx, 0xfffffffe2b: 8b 45 00 mov eax, DWORD PTR [ebp+0x0]2e: c1 e0 10 shl eax, 0x1031: c1 e8 10 shr eax, 0x1034: 89 c3 mov ebx, eax36: 09 fb or ebx, edi38: 21 f8 and eax, edi3a: f7 d0 not eax3c: 21 d8 and eax, ebx3e: 66 89 45 00 mov WORD PTR [ebp+0x0], ax42: 83 c5 02 add ebp, 0x245: 4a dec edx46: 85 d2 test edx, edx48: 0f 85 cf ff ff ff jne 0x1d4e: ec in al, dx4f: 37 aaa50: 75 5d jne 0xaf52: 7a 05 jp 0x5954: 28 ed sub ch, ch56: 24 ed and al, 0xed58: 24 ed and al, 0xed5a: 0b 88 7f eb 50 98 or ecx, DWORD PTR [eax-0x67af1481]60: 38 f9 cmp cl, bh62: 5c pop esp63: 96 xchg esi, eax64: 2b 96 70 fe c6 ff sub edx, DWORD PTR [esi-0x390190]6a: c6 (bad)6b: ff 9f 32 1f 58 1e call FWORD PTR [edi+0x1e581f32]71: 00 d3 add bl, dl73: 80 .byte 0x80
注意:代码基于x86-32架构。syscall的调用号所对应的功能可以在这里找到
提示:
你可以HOOKint 80h指令,二进制代码是cd 80,然后读取寄存器和内存。请记住,shellcode是可以在任何地址被加载执行的代码,绝大多数的shellcode使用栈来执行。
解决方案:
在本贴回复中(查看阅读原文,查看原帖)
任务3
可以从这里下载这个二进制文件。该代码使用了以下的编译选项:
gcc function.c -m32 -o function
源码如下:
int strcmp(char *a, char *b){//get lengthint len = 0;char *ptr = a;while(*ptr){ptr++;len++;}//comparestringsfor(int i=0; i<=len; i++){if (a[i]!=b[i])return 1;}return 0;}__attribute__((stdcall))int super_function(int a, char *b){if (a==5 && !strcmp(b, "batman")){return 1;}return 0;}int main(){super_function(1, "spiderman");}
任务是通过某种方法调用super_function使它返回1.
反汇编代码如下:
.text:0x8048464 super_function proc near ; CODE XREF: main+16p.text:0x8048464.text:0x8048464 arg_0 = dword ptr 8.text:0x8048464 arg_4 = dword ptr 0Ch.text:0x8048464.text:0x8048464 push ebp.text:0x8048465 mov ebp, esp.text:0x8048467 call __x86_get_pc_thunk_ax.text:0x804846C add eax, 1B94h.text:0x8048471 cmp [ebp+arg_0], 5.text:0x8048475 jnz short loc_8048494.text:0x8048477 lea eax, (aBatman - 804A000h)[eax] ; "batman".text:0x804847D push eax.text:0x804847E push [ebp+arg_4].text:0x8048481 call strcmp.text:0x8048486 add esp, 8.text:0x8048489 test eax, eax.text:0x804848B jnz short loc_8048494.text:0x804848D mov eax, 1.text:0x8048492 jmp short locret_8048499.text:0x8048494 ; ---------------------------------------------------------------------------.text:0x8048494.text:0x8048494 loc_8048494: ; CODE XREF: super_function+11j.text:0x8048494 ; super_function+27j.text:0x8048494 mov eax, 0.text:0x8048499.text:0x8048499 locret_8048499: ; CODE XREF: super_function+2Ej.text:0x8048499 leave.text:0x804849A retn 8.text:0x804849A super_function endp
提示:
根据STDCALL调用约定,当模拟开始的时候栈应该开起来像下边的这张图图片一样。在这张图片中,RET仅仅是返回某个地址(可以是任何值)。
解决方案:
在本贴回复中
任务4
这个任务和第一个很像。区别是目标架构不是x86而是小端ARM32
a@x:~/Desktop/unicorn_engine_lessons$ file task4task4: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=3dbf508680ba3d023d3422025954311e1d8fb4a1, not stripped
可以在这里下载到二进制文件
ARM调用约定可能会帮助到你
正确答案:
2635833876
提示:
函数的第一个参数通过R0传递(UC_ARM_REG_R0)
返回值同样在R0中
函数的第二个参数通过R1传递(UC_ARM_REG_R1)
可以通过mu = Uc (UC_ARCH_ARM,UC_MODE_LITTLE_ENDIAN)来初始化Unicorn。
解决方案:
在本贴回复中
备忘录
from unicorn import * - 加载Unicorn库。包含一些函数和基本的常量。
from unicorn.x86_const import* - 加载 X86 和X64架构相关的常量
所有unicorn模块中的常量
UC_API_MAJOR UC_ERR_VERSION UC_MEM_READ UC_PROT_ALLUC_API_MINOR UC_ERR_WRITE_PROT UC_MEM_READ_AFTER UC_PROT_EXECUC_ARCH_ARM UC_ERR_WRITE_UNALIGNED UC_MEM_READ_PROT UC_PROT_NONEUC_ARCH_ARM64 UC_ERR_WRITE_UNMAPPED UC_MEM_READ_UNMAPPED UC_PROT_READUC_ARCH_M68K UC_HOOK_BLOCK UC_MEM_WRITE UC_PROT_WRITEUC_ARCH_MAX UC_HOOK_CODE UC_MEM_WRITE_PROT UC_QUERY_MODEUC_ARCH_MIPS UC_HOOK_INSN UC_MEM_WRITE_UNMAPPED UC_QUERY_PAGE_SIZEUC_ARCH_PPC UC_HOOK_INTR UC_MILISECOND_SCALE UC_SECOND_SCALEUC_ARCH_SPARC UC_HOOK_MEM_FETCH UC_MODE_16 UC_VERSION_EXTRAUC_ARCH_X86 UC_HOOK_MEM_FETCH_INVALID UC_MODE_32 UC_VERSION_MAJORUC_ERR_ARCH UC_HOOK_MEM_FETCH_PROT UC_MODE_64 UC_VERSION_MINORUC_ERR_ARG UC_HOOK_MEM_FETCH_UNMAPPED UC_MODE_ARM UcUC_ERR_EXCEPTION UC_HOOK_MEM_INVALID UC_MODE_BIG_ENDIAN UcErrorUC_ERR_FETCH_PROT UC_HOOK_MEM_PROT UC_MODE_LITTLE_ENDIAN arm64_constUC_ERR_FETCH_UNALIGNED UC_HOOK_MEM_READ UC_MODE_MCLASS arm_constUC_ERR_FETCH_UNMAPPED UC_HOOK_MEM_READ_AFTER UC_MODE_MICRO debugUC_ERR_HANDLE UC_HOOK_MEM_READ_INVALID UC_MODE_MIPS3 m68k_constUC_ERR_HOOK UC_HOOK_MEM_READ_PROT UC_MODE_MIPS32 mips_constUC_ERR_HOOK_EXIST UC_HOOK_MEM_READ_UNMAPPED UC_MODE_MIPS32R6 sparc_constUC_ERR_INSN_INVALID UC_HOOK_MEM_UNMAPPED UC_MODE_MIPS64 uc_arch_supportedUC_ERR_MAP UC_HOOK_MEM_VALID UC_MODE_PPC32 uc_versionUC_ERR_MODE UC_HOOK_MEM_WRITE UC_MODE_PPC64 unicornUC_ERR_NOMEM UC_HOOK_MEM_WRITE_INVALID UC_MODE_QPX unicorn_constUC_ERR_OK UC_HOOK_MEM_WRITE_PROT UC_MODE_SPARC32 version_bindUC_ERR_READ_PROT UC_HOOK_MEM_WRITE_UNMAPPED UC_MODE_SPARC64 x86_constUC_ERR_READ_UNALIGNED UC_MEM_FETCH UC_MODE_THUMBUC_ERR_READ_UNMAPPED UC_MEM_FETCH_PROT UC_MODE_V8UC_ERR_RESOURCE UC_MEM_FETCH_UNMAPPED UC_MODE_V9
一些unicorn.x86_const中的常量
UC_X86_REG_EAXUC_X86_REG_RIPUC_X86_REG_RAX
mu = Uc(arch,mode) - 获取Uc实例。在这里指定目标架构,例如:
mu = Uc(UC_ARCH_X86,UC_MODE_64) - 获取X86-64架构的实例。
mu = Uc(UC_ARCH_X86,UC_MODE_32) - 获取X86-32架构的实例。
mu.mem_map(ADDRESS,4096) - 映射一片内存区域
mu.mem_write(ADDRESS,DATA) - 向内存中写入数据
tmp = mu.mem_read(ADDRESS,SIZE) - 从内存中读取数据
mu.reg_write(UC_X86_REG_ECX,0X0) - 设置ECX值。
r_esp = mu.reg_read(UC_X86_REG_ESP) - 读取ESP的值。
mu.emu_start(ADDRESS_START,ADDRESS_END) - 开始执行模拟。
命令追踪:
def hook_code(mu, address, size, user_data):print('>>> Tracing instruction at 0x%x, instruction size = 0x%x' %(address, size))mu.hook_add(UC_HOOK_CODE, hook_code)
这段代码添加了一个HOOK(向Unicorn引擎中),我们定义的函数会在执行每一条命令之前被执行。参数含义如下:
Uc实例
指令的地址
指令的长度
用户定义数据(通过hook_add()函数传递)
参考:
Unicorn引擎的基本介绍
Unicorn引擎支持的语言接口
Unicorn Engine Reference
official UE tutorial
本文由看雪翻译小组 zplusplus 编译,来源eternal
转载请注明来自看雪社区
热门阅读
点击阅读原文/read,
更多干货等着你~