查看原文
其他

Unicorn引擎教程(二)

2018-02-14 zplusplus 看雪学院


第一部分请查看: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 e8ffffffffc05d6a055b29dd83c54e89e96a02030c245b31d266ba12008b39c1e710c1ef1081e9feffffff8b4500c1e010c1e81089c309fb21f8f7d021d86689450083c5024a85d20f85cfffffffec37755d7a0528ed24ed24ed0b887feb509838f95c962b9670fec6ffc6ff9f321f581e00d380
   0:    e8 ff ff ff ff           call   0x4
   5:    c0 5d 6a 05              rcr    BYTE PTR [ebp+0x6a], 0x5
   9:    5b                       pop    ebx
   a:    29 dd                    sub    ebp, ebx
   c:    83 c5 4e                 add    ebp, 0x4e
   f:    89 e9                    mov    ecx, ebp
  11:    6a 02                    push   0x2
  13:    03 0c 24                 add    ecx, DWORD PTR [esp]
  16:    5b                       pop    ebx
  17:    31 d2                    xor    edx, edx
  19:    66 ba 12 00              mov    dx, 0x12
  1d:    8b 39                    mov    edi, DWORD PTR [ecx]
  1f:    c1 e7 10                 shl    edi, 0x10
  22:    c1 ef 10                 shr    edi, 0x10
  25:    81 e9 fe ff ff ff        sub    ecx, 0xfffffffe
  2b:    8b 45 00                 mov    eax, DWORD PTR [ebp+0x0]
  2e:    c1 e0 10                 shl    eax, 0x10
  31:    c1 e8 10                 shr    eax, 0x10
  34:    89 c3                    mov    ebx, eax
  36:    09 fb                    or     ebx, edi
  38:    21 f8                    and    eax, edi
  3a:    f7 d0                    not    eax
  3c:    21 d8                    and    eax, ebx
  3e:    66 89 45 00              mov    WORD PTR [ebp+0x0], ax
  42:    83 c5 02                 add    ebp, 0x2
  45:    4a                       dec    edx
  46:    85 d2                    test   edx, edx
  48:    0f 85 cf ff ff ff        jne    0x1d
  4e:    ec                       in     al, dx
  4f:    37                       aaa
  50:    75 5d                    jne    0xaf
  52:    7a 05                    jp     0x59
  54:    28 ed                    sub    ch, ch
  56:    24 ed                    and    al, 0xed
  58:    24 ed                    and    al, 0xed
  5a:    0b 88 7f eb 50 98        or     ecx, DWORD PTR [eax-0x67af1481]
  60:    38 f9                    cmp    cl, bh
  62:    5c                       pop    esp
  63:    96                       xchg   esi, eax
  64:    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, dl
  73:    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 length
    int len = 0;
    char *ptr = a;
    while(*ptr)
    {
        ptr++;
        len++;
    }
 
    //comparestrings
    for(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 task4
task4: 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_ALL
UC_API_MINOR                UC_ERR_WRITE_PROT           UC_MEM_READ_AFTER           UC_PROT_EXEC
UC_ARCH_ARM                 UC_ERR_WRITE_UNALIGNED      UC_MEM_READ_PROT            UC_PROT_NONE
UC_ARCH_ARM64               UC_ERR_WRITE_UNMAPPED       UC_MEM_READ_UNMAPPED        UC_PROT_READ
UC_ARCH_M68K                UC_HOOK_BLOCK               UC_MEM_WRITE                UC_PROT_WRITE
UC_ARCH_MAX                 UC_HOOK_CODE                UC_MEM_WRITE_PROT           UC_QUERY_MODE
UC_ARCH_MIPS                UC_HOOK_INSN                UC_MEM_WRITE_UNMAPPED       UC_QUERY_PAGE_SIZE
UC_ARCH_PPC                 UC_HOOK_INTR                UC_MILISECOND_SCALE         UC_SECOND_SCALE
UC_ARCH_SPARC               UC_HOOK_MEM_FETCH           UC_MODE_16                  UC_VERSION_EXTRA
UC_ARCH_X86                 UC_HOOK_MEM_FETCH_INVALID   UC_MODE_32                  UC_VERSION_MAJOR
UC_ERR_ARCH                 UC_HOOK_MEM_FETCH_PROT      UC_MODE_64                  UC_VERSION_MINOR
UC_ERR_ARG                  UC_HOOK_MEM_FETCH_UNMAPPED  UC_MODE_ARM                 Uc
UC_ERR_EXCEPTION            UC_HOOK_MEM_INVALID         UC_MODE_BIG_ENDIAN          UcError
UC_ERR_FETCH_PROT           UC_HOOK_MEM_PROT            UC_MODE_LITTLE_ENDIAN       arm64_const
UC_ERR_FETCH_UNALIGNED      UC_HOOK_MEM_READ            UC_MODE_MCLASS              arm_const
UC_ERR_FETCH_UNMAPPED       UC_HOOK_MEM_READ_AFTER      UC_MODE_MICRO               debug
UC_ERR_HANDLE               UC_HOOK_MEM_READ_INVALID    UC_MODE_MIPS3               m68k_const
UC_ERR_HOOK                 UC_HOOK_MEM_READ_PROT       UC_MODE_MIPS32              mips_const
UC_ERR_HOOK_EXIST           UC_HOOK_MEM_READ_UNMAPPED   UC_MODE_MIPS32R6            sparc_const
UC_ERR_INSN_INVALID         UC_HOOK_MEM_UNMAPPED        UC_MODE_MIPS64              uc_arch_supported
UC_ERR_MAP                  UC_HOOK_MEM_VALID           UC_MODE_PPC32               uc_version
UC_ERR_MODE                 UC_HOOK_MEM_WRITE           UC_MODE_PPC64               unicorn
UC_ERR_NOMEM                UC_HOOK_MEM_WRITE_INVALID   UC_MODE_QPX                 unicorn_const
UC_ERR_OK                   UC_HOOK_MEM_WRITE_PROT      UC_MODE_SPARC32             version_bind
UC_ERR_READ_PROT            UC_HOOK_MEM_WRITE_UNMAPPED  UC_MODE_SPARC64             x86_const
UC_ERR_READ_UNALIGNED       UC_MEM_FETCH                UC_MODE_THUMB              
UC_ERR_READ_UNMAPPED        UC_MEM_FETCH_PROT           UC_MODE_V8                 
UC_ERR_RESOURCE             UC_MEM_FETCH_UNMAPPED       UC_MODE_V9


一些unicorn.x86_const中的常量

UC_X86_REG_EAX
UC_X86_REG_RIP
UC_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,

更多干货等着你~

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存