调用汇编代码符号
前言
这里遇到了一个相关的CTF习题,看到其WP中的思路不错,特别学习一下
题目
  其是picoCTF的asm4,题目要求获取调用asm4("picoCTF_a3112")的结果,其中附件代码如下所示
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58asm4:
        <+0>:   push   ebp
        <+1>:   mov    ebp,esp
        <+3>:   push   ebx
        <+4>:   sub    esp,0x10
        <+7>:   mov    DWORD PTR [ebp-0x10],0x246
        <+14>:  mov    DWORD PTR [ebp-0xc],0x0
        <+21>:  jmp    0x518 <asm4+27>
        <+23>:  add    DWORD PTR [ebp-0xc],0x1
        <+27>:  mov    edx,DWORD PTR [ebp-0xc]
        <+30>:  mov    eax,DWORD PTR [ebp+0x8]
        <+33>:  add    eax,edx
        <+35>:  movzx  eax,BYTE PTR [eax]
        <+38>:  test   al,al
        <+40>:  jne    0x514 <asm4+23>
        <+42>:  mov    DWORD PTR [ebp-0x8],0x1
        <+49>:  jmp    0x587 <asm4+138>
        <+51>:  mov    edx,DWORD PTR [ebp-0x8]
        <+54>:  mov    eax,DWORD PTR [ebp+0x8]
        <+57>:  add    eax,edx
        <+59>:  movzx  eax,BYTE PTR [eax]
        <+62>:  movsx  edx,al
        <+65>:  mov    eax,DWORD PTR [ebp-0x8]
        <+68>:  lea    ecx,[eax-0x1]
        <+71>:  mov    eax,DWORD PTR [ebp+0x8]
        <+74>:  add    eax,ecx
        <+76>:  movzx  eax,BYTE PTR [eax]
        <+79>:  movsx  eax,al
        <+82>:  sub    edx,eax
        <+84>:  mov    eax,edx
        <+86>:  mov    edx,eax
        <+88>:  mov    eax,DWORD PTR [ebp-0x10]
        <+91>:  lea    ebx,[edx+eax*1]
        <+94>:  mov    eax,DWORD PTR [ebp-0x8]
        <+97>:  lea    edx,[eax+0x1]
        <+100>: mov    eax,DWORD PTR [ebp+0x8]
        <+103>: add    eax,edx
        <+105>: movzx  eax,BYTE PTR [eax]
        <+108>: movsx  edx,al
        <+111>: mov    ecx,DWORD PTR [ebp-0x8]
        <+114>: mov    eax,DWORD PTR [ebp+0x8]
        <+117>: add    eax,ecx
        <+119>: movzx  eax,BYTE PTR [eax]
        <+122>: movsx  eax,al
        <+125>: sub    edx,eax
        <+127>: mov    eax,edx
        <+129>: add    eax,ebx
        <+131>: mov    DWORD PTR [ebp-0x10],eax
        <+134>: add    DWORD PTR [ebp-0x8],0x1
        <+138>: mov    eax,DWORD PTR [ebp-0xc]
        <+141>: sub    eax,0x1
        <+144>: cmp    DWORD PTR [ebp-0x8],eax
        <+147>: jl     0x530 <asm4+51>
        <+149>: mov    eax,DWORD PTR [ebp-0x10]
        <+152>: add    esp,0x10
        <+155>: pop    ebx
        <+156>: pop    ebp
        <+157>: ret    
解题说明
  可以看到,要理清这五十多行的汇编代码,还是比较麻烦的。因此理想的方法是直接执行asm4("picoCTF_a3112")
因此一个合理的思路就是在C语言中直接进行符号调用即可
调用函数
  这个很简单,就是在C中调用该导出符号即可,如下所示
  1
2
3
4
5
6
7
8
extern int asm4(char *str);
int main(void) {
	printf("0x%x\n", asm4("picoCTF_a3112"));
	return 0;
}
汇编代码修改
  这明显是通过objdump反汇编出来的汇编代码,并且还附带这诸多的标记信息。
  我们首先需要将其转换为符合格式的汇编代码,即执行如下几个步骤
- 去除代码字节序数
- 去除跳转注解
- 添加跳转标签,统一为asm4_字节序数
- 修改跳转地址为相对应的跳转标签 - 最后整理完成的汇编代码如下所示 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62- asm4: 
 push ebp
 mov ebp,esp
 push ebx
 sub esp,0x10
 mov DWORD PTR [ebp-0x10],0x246
 mov DWORD PTR [ebp-0xc],0x0
 jmp asm4_27
 asm4_23:
 add DWORD PTR [ebp-0xc],0x1
 asm4_27:
 mov edx,DWORD PTR [ebp-0xc]
 mov eax,DWORD PTR [ebp+0x8]
 add eax,edx
 movzx eax,BYTE PTR [eax]
 test al,al
 jne asm4_23
 mov DWORD PTR [ebp-0x8],0x1
 jmp asm4_138
 asm4_51:
 mov edx,DWORD PTR [ebp-0x8]
 mov eax,DWORD PTR [ebp+0x8]
 add eax,edx
 movzx eax,BYTE PTR [eax]
 movsx edx,al
 mov eax,DWORD PTR [ebp-0x8]
 lea ecx,[eax-0x1]
 mov eax,DWORD PTR [ebp+0x8]
 add eax,ecx
 movzx eax,BYTE PTR [eax]
 movsx eax,al
 sub edx,eax
 mov eax,edx
 mov edx,eax
 mov eax,DWORD PTR [ebp-0x10]
 lea ebx,[edx+eax*1]
 mov eax,DWORD PTR [ebp-0x8]
 lea edx,[eax+0x1]
 mov eax,DWORD PTR [ebp+0x8]
 add eax,edx
 movzx eax,BYTE PTR [eax]
 movsx edx,al
 mov ecx,DWORD PTR [ebp-0x8]
 mov eax,DWORD PTR [ebp+0x8]
 add eax,ecx
 movzx eax,BYTE PTR [eax]
 movsx eax,al
 sub edx,eax
 mov eax,edx
 add eax,ebx
 mov DWORD PTR [ebp-0x10],eax
 add DWORD PTR [ebp-0x8],0x1
 asm4_138:
 mov eax,DWORD PTR [ebp-0xc]
 sub eax,0x1
 cmp DWORD PTR [ebp-0x8],eax
 jl asm4_51
 mov eax,DWORD PTR [ebp-0x10]
 add esp,0x10
 pop ebx
 pop ebp
 ret
生成可执行文件
其基本思路很简单——就是将两个部分皆编译、汇编成目标文件,然后进行链接即可,从而生成正常的可执行文件。
  对于C部分,其生成很简单;关键问题在于给定的汇编文件生成目标文件。如果此时直接执行gcc asm4.S,则程序会给出编译错误等信息。
其原因也很简单:虽然这是一份正确的汇编代码,但是其使用Intel格式书写;而一般编译器默认使用AT&T格式进行编译和汇编,从而导致无法正常生成目标文件;除此之外,该汇编代码部分还需要声明其符号,方便进行调用。
  因此修改过的汇编代码如下所示
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 noprefix
 asm4
asm4:
push   ebp
mov    ebp,esp
push   ebx
sub    esp,0x10
mov    DWORD PTR [ebp-0x10],0x246
mov    DWORD PTR [ebp-0xc],0x0
jmp    0x518 <asm4+27>
asm4_23:
add    DWORD PTR [ebp-0xc],0x1
asm4_27:
mov    edx,DWORD PTR [ebp-0xc]
mov    eax,DWORD PTR [ebp+0x8]
add    eax,edx
movzx  eax,BYTE PTR [eax]
test   al,al
jne    asm4_23
mov    DWORD PTR [ebp-0x8],0x1
jmp    asm4_138
asm4_51:
mov    edx,DWORD PTR [ebp-0x8]
mov    eax,DWORD PTR [ebp+0x8]
add    eax,edx
movzx  eax,BYTE PTR [eax]
movsx  edx,al
mov    eax,DWORD PTR [ebp-0x8]
lea    ecx,[eax-0x1]
mov    eax,DWORD PTR [ebp+0x8]
add    eax,ecx
movzx  eax,BYTE PTR [eax]
movsx  eax,al
sub    edx,eax
mov    eax,edx
mov    edx,eax
mov    eax,DWORD PTR [ebp-0x10]
lea    ebx,[edx+eax*1]
mov    eax,DWORD PTR [ebp-0x8]
lea    edx,[eax+0x1]
mov    eax,DWORD PTR [ebp+0x8]
add    eax,edx
movzx  eax,BYTE PTR [eax]
movsx  edx,al
mov    ecx,DWORD PTR [ebp-0x8]
mov    eax,DWORD PTR [ebp+0x8]
add    eax,ecx
movzx  eax,BYTE PTR [eax]
movsx  eax,al
sub    edx,eax
mov    eax,edx
add    eax,ebx
mov    DWORD PTR [ebp-0x10],eax
add    DWORD PTR [ebp-0x8],0x1
asm4_138:
mov    eax,DWORD PTR [ebp-0xc]
sub    eax,0x1
cmp    DWORD PTR [ebp-0x8],eax
jl     asm4_51
mov    eax,DWORD PTR [ebp-0x10]
add    esp,0x10
pop    ebx
pop    ebp
ret    
  通过添加上面两个注解,方便编译器等进行编译和链接。
  其最后编译和链接时,仍需要传递相关的参数,表明采用Intel格式的汇编代码,如下所示
  1
2gcc -m32 -c -masm=intel asm4.S
gcc -m32 asm4.S exp.c
  最后执行,结果如下所示
  1
2$ ./a.out
0x1d0

