栈溢出笔记1.5 换一个汇编工具
前面的內(nèi)容中我們使用VC++內(nèi)聯(lián)匯編,雖然很方便,但是無(wú)法定義字符串常量,導(dǎo)致我們需要把字符串的ASCII碼找到,再一個(gè)一個(gè)壓入棧中,比較繁瑣,本節(jié),我們換一個(gè)匯編工具——nasm,選擇它是因?yàn)樗梢钥缙脚_(tái)使用。
有了這個(gè)匯編工具,我們就可以定義字符串常量了,例如:
/*****************************************************************************/ DB “example_1”, 0x00 DB “HelloWorld”, 0x00 /*****************************************************************************/- 1
- 2
- 3
- 4
這樣方便是方便了,但是出現(xiàn)了新的問(wèn)題,我們不可能寫(xiě)成這個(gè)樣子:
/*****************************************************************************/ push ebp mov ebp, esp db “example_1”, 0x00 db “HelloWorld”, 0x00 db “user32.dll”, 0x00 lea ebx, [ebp-24h] push ebx mov ebx, 0x7c801d7b call ebx // LoadLibraryA /*****************************************************************************/- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
因?yàn)槿齻€(gè)字符串為數(shù)據(jù),而不是指令,不可能夾在指令中間,這樣會(huì)讓CPU將數(shù)據(jù)當(dāng)做指令運(yùn)行,程序跑飛。因此,只能放在指令區(qū)域之外。但是,又必須放在代碼段中,因?yàn)镾hellcode只有指令,沒(méi)有數(shù)據(jù)段。因此,有了下面這種經(jīng)典的做法:將字符串定義放置到一條CALL指令之后,由于CALL指令會(huì)將返回地址壓棧,此時(shí)壓入棧中的地址就為第一個(gè)字符串的地址,從而,我們可以在此后的代碼中在棧上獲取該字符串的地址。如下結(jié)構(gòu):
/*****************************************************************************/ JMP short GetString RunMsgBox: ... GetString: CALL RunMsgBox DB “example_1” DB “HelloWorld” /*****************************************************************************/- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
這種結(jié)構(gòu)就充分說(shuō)明了指令和數(shù)據(jù)并不區(qū)分,本來(lái)CALL指令用來(lái)在棧上保存指令,結(jié)果現(xiàn)在被用來(lái)保存數(shù)據(jù)了。
下面就是利用上述結(jié)構(gòu)編寫(xiě)的匯編程序:
/*****************************************************************************/ // example_8 nasm下的匯編Shellcode SECTION .textBITS 32global _main_main: jmp short GetStringRunMsgBox: pop ebx push ebx ; "user32.dll" mov eax, 0x7c801d7b ; LoadLibraryA call eax xor eax,eax push eax lea ebx, [ebx+11] ; "example_1" push ebx lea ebx, [ebx+10] ; "HelloWorld" push ebx push eax mov ebx, 0x77d507ea ; MessageBoxA call ebx push eax mov ebx, 0x7c81cafa ; ExitProcess call ebx GetString: call RunMsgBox db "user32.dll", 0x00 db "example_1", 0x00 db "HelloWorld", 0x00 /*****************************************************************************/- 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
RunMsgBox中第一句pop ebx就將“user32.dll”的首地址保存在了ebx,這里注意與棧不同,后面的ebx地址是加而不是減。使用命令:
nasm -f win32 example_8.asm
編譯為obj文件。然后使用VS的cl.exe,鏈接為exe:
cl example_8.obj libcmt.lib
運(yùn)行exe,成功:
?
圖34
下面我們?cè)贗mmunity Debugger來(lái)看看:?
?
圖35
這一段就是完整的代碼,可見(jiàn),字符串?dāng)?shù)據(jù)全部被反匯編為指令了,上圖中標(biāo)出了三個(gè)字符串的結(jié)尾符。
標(biāo)出了結(jié)尾符之后,問(wèn)題也就來(lái)了,是的,空字節(jié),又出現(xiàn)了空字節(jié),而且這次更不好處理,因?yàn)槲覀冎挥昧俗址氖椎刂贰榱瞬怀霈F(xiàn)空字節(jié),我們定義字符串的時(shí)候不能加0x00結(jié)束符,但是使用字符串的時(shí)候又需要該結(jié)束符,而且,這樣定義的字符串位于代碼段,代碼段是不可寫(xiě)的,也就是一旦定義,不可修改。所以,如果空字節(jié)會(huì)引起問(wèn)題,就不要這樣定義。使用直接壓棧的方法反而容易處理。
使用nasm有個(gè)好處,就是可以直接編譯為bin格式,即操作碼,例如:
nasm -f bin -o example_8.bin example_8.asm
用HexEdit打開(kāi)example_8.bin,如下:
?
圖36
這樣,可以簡(jiǎn)單的寫(xiě)個(gè)程序?qū)in文件寫(xiě)出為Shellcode,就不用再去Immunity Debugger一個(gè)字節(jié)一個(gè)字節(jié)的摳出來(lái)了。
總結(jié)
以上是生活随笔為你收集整理的栈溢出笔记1.5 换一个汇编工具的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: (计算机组成原理)第三章存储系统-第四节
- 下一篇: 从0到100——知乎架构变迁史