深入探索汇编语言与反汇编器的技术实现

本文详细介绍了作者在2002年学习汇编语言时开发的反汇编器项目,通过实际代码演示如何将二进制程序还原为可编译的源代码,涵盖ELF格式解析、代码与数据分离等技术细节。

拦截星球!:幕后故事

每个"真正"的研究者生活中总有这样一个时刻:你开始着手做一些实际可能并不需要但极具教育意义的事情。解决这些问题来扩展视野和提升技能是很有趣的,特别是当你对某个奇思妙想产生痴迷状态时。对我来说,2002年的主要痴迷之一就是想要做出一些还不存在的东西,或者即使存在,也不能如我所愿地工作,而且当然不是我做的(该死)。同样的痴迷促使我创建了拦截器,但这篇文章是关于另一个完全不同的项目。

那时我想掌握汇编语言,因为这是真正大师的语言,而且当时"真正的黑客必须懂汇编"的想法在我脑海中根深蒂固。在SoftICE中盲目地将jz替换为jnz当然能在简单的应用程序上产生一些结果,但我想要更多。为了理解这种计算机魔法,我想不出比编写自己的反汇编器更好的方法了。同样,反汇编器也各不相同。简单的指令列表并不能满足我,我想要得到可以直接汇编并获得与原始二进制文件相同的工作二进制文件的源代码。我不会深入探讨诸如代码与数据分离等具体问题,而只是展示最终的结果。

演示1 - 反汇编我自己的汇编端口扫描器。所有符号(变量名和子函数名)都存在于ELF中。

  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
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/*
 *|--------------------------------------
 *| 0x4553_Reconstructor
 *| 检测到ELF格式
 *| 开始反汇编 [test]
 *| 入口点.........[8048074]
 *| .text段大小.....[564]
 *| .data段大小.....[0]
 *| .data段地址.....[80492a8]
 *| 找到.symtab
 *| 找到.strtab
 *|--------------------------------------
 */

/* 读取常量值...(如果存在) */
STDOUT=1
AF_INET=2
SOCK_STREAM=1
IPPROTO_IP=0
NULL=0
SYS_exit=1
SYS_read=3
SYS_write=4
SYS_socketcall=102
SYS_socket=1
SYS_connect=3
sys=128
SIZEOF_SA=16
SIN_FAMILY=-16
SIN_PORT=-14
SIN_ADDR=-12
SIN_ZERO0=-8
SIN_ZERO1=-4
SA=-16
ARGS=-32
SOCK=-32
ARG0=-32
ARG1=-28
ARG2=-24
ARG3=-20
SOCK_BUF=-544
PORT=1
END_PORT=100
X=-16
counter=-20
uselen=31
__bss_start=134517416
_edata=134517416
_end=134517440

/* 读取对象...(如果存在) */

/* 80492a8: */ .bss   /**/
/* 80492a8: */ .lcomm ip_addr,16
/* 80492b8: */ .lcomm this_digit,4
/* 80492bc: */ .lcomm ip_number,4

/* 8048074: */ .text   /**/
.globl _start

/* 8048074: */ _start:

/* 8048074: 5b */ pop      %ebx

/* 8048075: 83 fb 01 */ cmp      $0x1,%ebx

/* 8048078: 0f 84 aa 01 00 00 */ jz       usage

/* 804807e: 5b */ pop      %ebx

/* 804807f: 5b */ pop      %ebx

/* 8048080: 85 db */ test     %ebx,%ebx

/* 8048082: 0f 84 a3 00 00 00 */ jz       done_cmd

/* 8048088: 8a 03 */ movb     (%ebx),%al

/* 804808a: 43 */ inc      %ebx

/* 804808b: 3c 2d */ cmp      $0x2d,%al

/* 804808d: 0f 85 95 01 00 00 */ jnz      usage

/* 8048093: 8a 03 */ movb     (%ebx),%al

/* 8048095: 3c 74 */ cmp      $0x74,%al

/* 8048097: 0f 85 8b 01 00 00 */ jnz      usage

/* 804809d: 43 */ inc      %ebx

/* 804809e: 43 */ inc      %ebx
/* 804809f: 8d 3d a8 92 04 08 */ leal     ip_addr,%edi
/* 80480a5: b0 2e */ movb  $0x2e,%al
/* 80480a7: aa */ stosb

/* 80480a8: */ nextchar:
/* 80480a8: 8a 03 */ movb     (%ebx),%al
/* 80480aa: aa */ stosb
/* 80480ab: 84 c0 */ test     %al,%al
/* 80480ad: 74 03 */ jz       breakchar
/* 80480af: 43 */ inc      %ebx
/* 80480b0: e2 f6 */ loop     nextchar

/* 80480b2: */ breakchar:
/* 80480b2: 4f */ dec      %edi
/* 80480b3: 4f */ dec      %edi
/* 80480b4: 89 fe */ mov     %edi,%esi
/* 80480b6: b9 04 00 00 00 */ mov      $SYS_write,%ecx
/* 80480bb: c7 05 bc 92 04 08 00 00 00 00 */movl     $0x0000,ip_number
/* 80480c5: fd */ std

/* 80480c6: */ next_ip_byte:
/* 80480c6: c7 05 b8 92 04 08 00 00 00 00 */movl     $0x0000,this_digit
/* 80480d0: ac */ lodsb
/* 80480d1: 3c 2e */ cmp      $0x2e,%al
/* 80480d3: 75 01 */ jnz      not_dot
/* 80480d5: ac */ lodsb

/* 80480d6: */ not_dot:
/* 80480d6: 2c 30 */ sub      $0x30,%al
/* 80480d8: 00 05 b8 92 04 08 */ add      %al, this_digit
/* 80480de: ac */ lodsb
/* 80480df: 3c 2e */ cmp      $0x2e,%al
/* 80480e1: 74 2f */ jz       dot
/* 80480e3: 2c 30 */ sub      $0x30,%al
/* 80480e5: 89 c2 */ mov     %eax,%edx
/* 80480e7: d1 e0 */ shl      $1,%eax
/* 80480e9: c1 e2 03 */ shl      $0x3,%edx
/* 80480ec: 00 d0 */ add      %dl,%al
/* 80480ee: 00 05 b8 92 04 08 */ add      %al, this_digit
/* 80480f4: ac */ lodsb
/* 80480f5: 3c 2e */ cmp      $0x2e,%al
/* 80480f7: 74 19 */ jz       dot
/* 80480f9: 2c 30 */ sub      $0x30,%al
/* 80480fb: 89 c3 */ mov     %eax,%ebx
/* 80480fd: 89 c2 */ mov     %eax,%edx
/* 80480ff: c1 e0 02 */ shl      $0x2,%eax
/* 8048102: c1 e3 05 */ shl      $0x5,%ebx
/* 8048105: c1 e2 06 */ shl      $0x6,%edx
/* 8048108: 00 d8 */ add      %bl,%al
/* 804810a: 00 d0 */ add      %dl,%al
/* 804810c: 00 05 b8 92 04 08 */ add      %al, this_digit

/* 8048112: */ dot:
/* 8048112: 89 c8 */ mov     %ecx,%eax
/* 8048114: 49 */ dec      %ecx
/* 8048115: c1 e1 03 */ shl      $0x3,%ecx
/* 8048118: 8b 15 b8 92 04 08 */ mov      this_digit, %edx
/* 804811e: d3 e2 */ shl      %cl,%edx
/* 8048120: 01 15 bc 92 04 08 */ add      %edx, ip_number
/* 8048126: 89 c1 */ mov     %eax,%ecx
/* 8048128: e2 9c */ loop     next_ip_byte
/* 804812a: fc */ cld

/* 804812b: */ done_cmd:
/* 804812b: 55 */ push     %ebp
/* 804812c: 89 e5 */ mov     %esp,%ebp
/* 804812e: bf 01 00 00 00 */ mov      $STDOUT,%edi

/* 8048133: */ loop:
/* 8048133: 89 f8 */ mov     %edi,%eax
/* 8048135: 66 c1 c0 08 */ rol      $0x8,%ax
/* 8048139: c7 45 f0 02 00 00 00 */ movl     $0x00000002,0xfffffff0(%ebp)
/* 8048140: 89 45 f2 */ movl     %eax,0xfffffff2(%ebp)
/* 8048143: a1 bc 92 04 08 */ mov      ip_number,%eax
/* 8048148: 89 45 f4 */ movl     %eax,0xfffffff4(%ebp)
/* 804814b: c7 45 f8 00 00 00 00 */ movl     $0x00000000,0xfffffff8(%ebp)
/* 8048152: c7 45 fc 00 00 00 00 */ movl     $0x00000000,0xfffffffc(%ebp)
/* 8048159: b8 66 00 00 00 */ mov      $SYS_socketcall,%eax
/* 804815e: bb 01 00 00 00 */ mov      $STDOUT,%ebx
/* 8048163: c7 45 e0 02 00 00 00 */ movl     $0x00000002,0xffffffe0(%ebp)
/* 804816a: c7 45 e4 01 00 00 00 */ movl     $0x00000001,0xffffffe4(%ebp)
/* 8048171: c7 45 e8 00 00 00 00 */ movl     $0x00000000,0xffffffe8(%ebp)
/* 8048178: 8d 4d e0 */ leal     0xffffffe0(%ebp),%ecx
/* 804817b: cd 80 */ int      $0x80
/* 804817d: 83 f8 00 */ cmp      $0x0,%eax
/* 8048180: 0f 8c b1 00 00 00 */ jl       exit
/* 8048186: 89 45 e0 */ movl     %eax,0xffffffe0(%ebp)
/* 8048189: 40 */ inc      %eax
/* 804818a: b8 66 00 00 00 */ mov      $SYS_socketcall,%eax
/* 804818f: bb 03 00 00 00 */ mov      $SYS_read,%ebx
/* 8048194: 8d 55 f0 */ leal     0xfffffff0(%ebp),%edx
/* 8048197: 89 55 e4 */ movl     %edx,0xffffffe4(%ebp)
/* 804819a: c7 45 e8 10 00 00 00 */ movl     $0x00000010,0xffffffe8(%ebp)
/* 80481a1: 8d 4d e0 */ leal     0xffffffe0(%ebp),%ecx
/* 80481a4: cd 80 */ int      $0x80
/* 80481a6: 83 f8 00 */ cmp      $0x0,%eax
/* 80481a9: 7c 59 */ jl       next
/* 80481ab: b9 75 82 04 08 */ mov      $str,%ecx
/* 80481b0: ba 06 00 00 00 */ mov      $0x00000006, %edx
/* 80481b5: e8 63 00 00 00 */ call     pr_sock
/* 80481ba: b8 03 00 00 00 */ mov      $SYS_read,%eax
/* 80481bf: 8b 5d e0 */ movl     0xffffffe0(%ebp),%ebx
/* 80481c2: 8d 8d e0 fd ff ff */ leal     0xfffffde0(%ebp),%ecx
/* 80481c8: ba 32 00 00 00 */ mov      $0x00000032, %edx
/* 80481cd: cd 80 */ int      $0x80
/* 80481cf: 89 f8 */ mov     %edi,%eax
/* 80481d1: e8 68 00 00 00 */ call     int2ascii

/* 80481d6: */ return:
/* 80481d6: b9 7c 82 04 08 */ mov      $open,%ecx
/* 80481db: ba 09 00 00 00 */ mov      $0x00000009, %edx
/* 80481e0: e8 2b 00 00 00 */ call     pr_std
/* 80481e5: 8d 8d e0 fd ff ff */ leal     0xfffffde0(%ebp),%ecx
/* 80481eb: ba 1e 00 00 00 */ mov      $0x0000001e, %edx
/* 80481f0: e8 1b 00 00 00 */ call     pr_std
/* 80481f5: b9 a5 82 04 08 */ mov      $cr,%ecx
/* 80481fa: ba 02 00 00 00 */ mov      $AF_INET,%edx
/* 80481ff: e8 0c 00 00 00 */ call     pr_std

/* 8048204: */ next:
/* 8048204: 47 */ inc      %edi
/* 8048205: 89 f8 */ mov     %edi,%eax
/* 8048207: 3c 65 */ cmp      $0x65,%al
/* 8048209: 74 2c */ jz       exit
/* 804820b: e9 23 ff ff ff */ jmp      loop

/* 8048210: */ pr_std:
/* 8048210: b8 04 00 00 00 */ mov      $SYS_write,%eax
/* 8048215: bb 01 00 00 00 */ mov      $STDOUT,%ebx
/* 804821a: cd 80 */ int      $0x80
/* 804821c: c3 */ ret

/* 804821d: */ pr_sock:
/* 804821d: b8 04 00 00 00 */ mov      $SYS_write,%eax
/* 8048222: 8b 5d e0 */ movl     0xffffffe0(%ebp),%ebx
/* 8048225: cd 80 */ int      $0x80
/* 8048227: c3 */ ret

/* 8048228: */ usage:
/* 8048228: b9 86 82 04 08 */ mov      $use,%ecx
/* 804822d: ba 1f 00 00 00 */ mov      $uselen,%edx
/* 8048232: e8 d9 ff ff ff */ call     pr_std

/* 8048237: */ exit:
/* 8048237: b8 01 00 00 00 */ mov      $STDOUT,%eax
/* 804823c: cd 80 */ int      $0x80

/* 804823e: */ int2ascii:
/* 804823e: 31 f6 */ xor      %esi,%esi

/* 8048240: */ loop1:
/* 8048240: ba 00 00 00 00
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计