文字列と配列とポインタの逆アセンブルを見てみた。ポインタに関してはデバッガでメモリ内のデータの動きを追ってみた。
文字列
ソースコード
#include <stdio.h>
int main(void)
{
char str[] = "Hello World";
printf("%s\n", str);
return 0;
}
コンパイルgcc string_test.c -o string_test.out -fno-pie -fno-stack-protector -m32
実行結果
$ ./string_test.out
Hello World
逆アセンブルを出力objdump -d -M intel string_test.out
0804841d <main>:
804841d: 55 push ebp
804841e: 89 e5 mov ebp,esp
8048420: 83 e4 f0 and esp,0xfffffff0
8048423: 83 ec 20 sub esp,0x20
8048426: c7 44 24 14 48 65 6c mov DWORD PTR [esp+0x14],0x6c6c6548 ; 'lleH'
804842d: 6c
804842e: c7 44 24 18 6f 20 57 mov DWORD PTR [esp+0x18],0x6f57206f ; 'oW o'
8048435: 6f
8048436: c7 44 24 1c 72 6c 64 mov DWORD PTR [esp+0x1c],0x646c72 ; 'dlr'
804843d: 00
804843e: 8d 44 24 14 lea eax,[esp+0x14] ; 'load "Hello World" to eax'
8048442: 89 04 24 mov DWORD PTR [esp],eax
8048445: e8 a6 fe ff ff call 80482f0 <puts@plt>
804844a: b8 00 00 00 00 mov eax,0x0
804844f: c9 leave
8048450: c3 ret
8048451: 66 90 xchg ax,ax
8048453: 66 90 xchg ax,ax
8048455: 66 90 xchg ax,ax
8048457: 66 90 xchg ax,ax
8048459: 66 90 xchg ax,ax
804845b: 66 90 xchg ax,ax
804845d: 66 90 xchg ax,ax
804845f: 90 nop
配列
ソースコード
#include <stdio.h>
int main(void)
{
int i;
int array[5] = {1, 2, 3, 4, 5};
for (i = 0; i < 5; i++) {
printf("%d\n", array[i]);
}
return 0;
}
コンパイルgcc array_test.c -o array_test.out -fno-pie -fno-stack-protector -m32
実行結果
$ ./array_test.out
1
2
3
4
5
逆アセンブルを出力objdump -d -M intel array_test.out
0804841d <main>:
804841d: 55 push ebp
804841e: 89 e5 mov ebp,esp
8048420: 83 e4 f0 and esp,0xfffffff0
8048423: 83 ec 30 sub esp,0x30
8048426: c7 44 24 18 01 00 00 mov DWORD PTR [esp+0x18],0x1
804842d: 00
804842e: c7 44 24 1c 02 00 00 mov DWORD PTR [esp+0x1c],0x2
8048435: 00
8048436: c7 44 24 20 03 00 00 mov DWORD PTR [esp+0x20],0x3
804843d: 00
804843e: c7 44 24 24 04 00 00 mov DWORD PTR [esp+0x24],0x4
8048445: 00
8048446: c7 44 24 28 05 00 00 mov DWORD PTR [esp+0x28],0x5
804844d: 00
804844e: c7 44 24 2c 00 00 00 mov DWORD PTR [esp+0x2c],0x0
8048455: 00
8048456: eb 1d jmp 8048475 <main+0x58>
8048458: 8b 44 24 2c mov eax,DWORD PTR [esp+0x2c] ; 'esp+0x2c is an iterator'
804845c: 8b 44 84 18 mov eax,DWORD PTR [esp+eax*4+0x18]
8048460: 89 44 24 04 mov DWORD PTR [esp+0x4],eax
8048464: c7 04 24 20 85 04 08 mov DWORD PTR [esp],0x8048520
804846b: e8 80 fe ff ff call 80482f0 <printf@plt>
8048470: 83 44 24 2c 01 add DWORD PTR [esp+0x2c],0x1 ; 'increment iterator'
8048475: 83 7c 24 2c 04 cmp DWORD PTR [esp+0x2c],0x4 ; 'check if iterator reached 4. If yes exit the function, if no continue loop'
804847a: 7e dc jle 8048458 <main+0x3b>
804847c: b8 00 00 00 00 mov eax,0x0
8048481: c9 leave
8048482: c3 ret
8048483: 66 90 xchg ax,ax
8048485: 66 90 xchg ax,ax
8048487: 66 90 xchg ax,ax
8048489: 66 90 xchg ax,ax
804848b: 66 90 xchg ax,ax
804848d: 66 90 xchg ax,ax
804848f: 90 nop
ポインタ
ソースコード
#include <stdio.h>
int main(void)
{
int original_data = 1000;
int *my_pointer;
my_pointer = &original_data;
printf("%d\n", *my_pointer);
return 0;
}
コンパイルgcc pointer_test.c -o pointer_test.out -fno-pie -fno-stack-protector -m32
実行結果
$ ./pointer_test.out
1000
逆アセンブルを出力objdump -d -M intel pointer_test.out
0804841d <main>:
804841d: 55 push ebp
804841e: 89 e5 mov ebp,esp
8048420: 83 e4 f0 and esp,0xfffffff0
8048423: 83 ec 20 sub esp,0x20
8048426: c7 44 24 18 e8 03 00 mov DWORD PTR [esp+0x18],0x3e8 ; 'copy 1000 to the memory address specified by esp+0x18'
804842d: 00
804842e: 8d 44 24 18 lea eax,[esp+0x18] ; 'load the memory address specified by esp+0x18 to EAX. esp+0x18 stores 1000 hence EAX register will point to 1000'
8048432: 89 44 24 1c mov DWORD PTR [esp+0x1c],eax ; 'copy the memory address stored at EAX (which is a pointer to 1000) to the memory address specified by esp+0x1c'
8048436: 8b 44 24 1c mov eax,DWORD PTR [esp+0x1c] ; 'copy value at esp+0x1c (which is a pointer to 1000) to EAX'
804843a: 8b 00 mov eax,DWORD PTR [eax] ; 'copy the value pointed by EAX to EAX. EAX is a pointer to 1000. This instruction will copy the actual value 1000 to EAX'
804843c: 89 44 24 04 mov DWORD PTR [esp+0x4],eax ; 'copy 1000 to the memory address specified by esp+0x4'
8048440: c7 04 24 f0 84 04 08 mov DWORD PTR [esp],0x80484f0 ; 'copy "%d\n" to esp'
8048447: e8 a4 fe ff ff call 80482f0 <printf@plt>
804844c: b8 00 00 00 00 mov eax,0x0
8048451: c9 leave
8048452: c3 ret
8048453: 66 90 xchg ax,ax
8048455: 66 90 xchg ax,ax
8048457: 66 90 xchg ax,ax
8048459: 66 90 xchg ax,ax
804845b: 66 90 xchg ax,ax
804845d: 66 90 xchg ax,ax
804845f: 90 nop
デバッグしながらメモリ内のデータを確認してみる
8048426: c7 44 24 18 e8 03 00 mov DWORD PTR [esp+0x18],0x3e8 ; 'copy 1000 to the memory address specified by esp+0x18'
Breakpoint 3, 0x0804842e in main ()
(gdb) x/x $esp+0x18
0xffffd0b8: 0x000003e8
アドレスesp+0x18
に値0x3e8
(1000)がコピーされた。
804842e: 8d 44 24 18 lea eax,[esp+0x18] ; 'load the memory address specified by esp+0x18 to EAX. esp+0x18 stores 1000 hence EAX register will point to 1000'
(gdb) i r
eax 0x1 1
ecx 0xacd87d2d -1395098323
edx 0xffffd0f4 -12044
ebx 0xf7fb4000 -134529024
esp 0xffffd0a0 0xffffd0a0
ESPのアドレスは0xffffd0a0
。よってesp+0x18
のアドレスは0xffffd0a0 + 0x18
で0xffffd0b8
となる。
(gdb) ni
0x08048432 in main ()
(gdb) i r
eax 0xffffd0b8 -12104
ecx 0xe4cd748d -456297331
edx 0xffffd0f4 -12044
ebx 0xf7fb4000 -134529024
esp 0xffffd0a0 0xffffd0a0
ebp 0xffffd0c8 0xffffd0c8
esi 0x0 0
edi 0x0 0
eip 0x8048432 0x8048432 <main+21>
eflags 0x286 [ PF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) x/x $eax
0xffffd0b8: 0x000003e8
EAXにesp+0x18
のアドレス0xffffd0b8
がコピーされた。アドレス0xffffd0b8
には値0x3e8
(1000)が格納されている。これによりEAXは値0x3e8
(1000)をポイントするようになった。
- EAXにはアドレス
0xffffd0b8
が格納されている → アドレス0xffffd0b8
には値0x3e8
(1000)が格納されている
8048432: 89 44 24 1c mov DWORD PTR [esp+0x1c],eax ; 'copy the memory address stored at EAX (which is a pointer to 1000) to the memory address specified by esp+0x1c'
(gdb) i r
eax 0xffffd0b8 -12104
ecx 0xacd87d2d -1395098323
edx 0xffffd0f4 -12044
ebx 0xf7fb4000 -134529024
esp 0xffffd0a0 0xffffd0a0
ebp 0xffffd0c8 0xffffd0c8
esi 0x0 0
edi 0x0 0
eip 0x8048436 0x8048436 <main+25>
eflags 0x286 [ PF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) x/x $esp+0x1c
0xffffd0bc: 0xffffd0b8
EAXに格納されているアドレス0xffffd0b8
がesp+0x1c
にコピーされた。
8048436: 8b 44 24 1c mov eax,DWORD PTR [esp+0x1c] ; 'copy value at esp+0x1c (which is a pointer to 1000) to EAX'
(gdb) x/x $eax
0xffffd0b8: 0x000003e8
(gdb) ni
0x0804843a in main ()
(gdb) x/x $eax
0xffffd0b8: 0x000003e8
esp+0x1c
からEAXにアドレス0xffffd0b8
がコピーされた。アドレス0xffffd0b8
には値0x3e8
(1000)が格納されている。
804843a: 8b 00 mov eax,DWORD PTR [eax] ; 'copy the value pointed by EAX to EAX. EAX is a pointer to 1000. This instruction will copy the actual value 1000 to EAX'
Breakpoint 1, 0x0804843a in main ()
(gdb) i r
eax 0xffffd0b8 -12104
ecx 0xdecf3cd5 -556843819
edx 0xffffd0f4 -12044
ebx 0xf7fb4000 -134529024
esp 0xffffd0a0 0xffffd0a0
ebp 0xffffd0c8 0xffffd0c8
esi 0x0 0
edi 0x0 0
eip 0x804843a 0x804843a <main+29>
eflags 0x286 [ PF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) x/x $eax
0xffffd0b8: 0x000003e8
mov eax,DWORD PTR [eax]
実行前のレジスタ及びメモリの状態。EAXにはアドレス0xffffd0b8
が格納されている。このアドレスは値0x3e8
(1000)をポイントしている。
(gdb) ni
0x0804843c in main ()
(gdb) i r
eax 0x3e8 1000
ecx 0xdecf3cd5 -556843819
edx 0xffffd0f4 -12044
ebx 0xf7fb4000 -134529024
esp 0xffffd0a0 0xffffd0a0
ebp 0xffffd0c8 0xffffd0c8
esi 0x0 0
edi 0x0 0
eip 0x804843c 0x804843c <main+31>
eflags 0x286 [ PF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) x/x $eax
0x3e8: Cannot access memory at address 0x3e8
(gdb) p $eax
$1 = 1000
mov eax,DWORD PTR [eax]
実行後のレジスタ及びメモリの状態。アドレス0xffffd0b8
から値0x3e8
(1000)がEAXにコピーされた。mov命令実行前はEAXには0x3e8
(1000)を指しているアドレス0xffffd0b8
が格納されていたが、mov命令実行後は0x3e8
という値そのものがEAXにコピーされた。
804843c: 89 44 24 04 mov DWORD PTR [esp+0x4],eax ; 'copy 1000 to the memory address specified by esp+0x4'
(gdb) ni
0x08048440 in main ()
(gdb) x/x $esp+0x4
0xffffd0a4: 0x000003e8
esp+0x4
に値0x3e8
(1000)がコピーされた。
8048440: c7 04 24 f0 84 04 08 mov DWORD PTR [esp],0x80484f0 ; 'copy "%d\n" to esp'
8048447: e8 a4 fe ff ff call 80482f0 <printf@plt>
(gdb) ni
0x08048447 in main ()
(gdb) x/s 0x80484f0
0x80484f0: "%d\n"
アドレス0x80484f0
には書式文字列と改行 %d\n
が格納されていた。
参考
Learning Malware Analysis (By Monnappa K A) P.112 - 114
Practical Malware Analysis (by Michael Sikorski and Andrew Honig) P.73 - 74