栈溢出笔记1.5 换一个汇编工具

来源:互联网 发布:淘宝下载器 编辑:程序博客网 时间:2024/04/27 21:50

前面的内容中我们使用VC++内联汇编,虽然很方便,但是无法定义字符串常量,导致我们需要把字符串的ASCII码找到,再一个一个压入栈中,比较繁琐,本节,我们换一个汇编工具——nasm,选择它是因为它可以跨平台使用。

有了这个汇编工具,我们就可以定义字符串常量了,例如:

/*****************************************************************************/DB  “example_1”, 0x00DB  “HelloWorld”, 0x00/*****************************************************************************/

这样方便是方便了,但是出现了新的问题,我们不可能写成这个样子:

/*****************************************************************************/push    ebp        mov ebp, esp        db      “example_1”, 0x00db      “HelloWorld”, 0x00db      “user32.dll”, 0x00        lea     ebx, [ebp-24h]        push    ebx        mov ebx, 0x7c801d7b         call        ebx // LoadLibraryA/*****************************************************************************/

因为三个字符串为数据,而不是指令,不可能夹在指令中间,这样会让CPU将数据当做指令运行,程序跑飞。因此,只能放在指令区域之外。但是,又必须放在代码段中,因为Shellcode只有指令,没有数据段。因此,有了下面这种经典的做法:将字符串定义放置到一条CALL指令之后,由于CALL指令会将返回地址压栈,此时压入栈中的地址就为第一个字符串的地址,从而,我们可以在此后的代码中在栈上获取该字符串的地址。如下结构:

/*****************************************************************************/ JMP short GetStringRunMsgBox:...GetString:CALL RunMsgBoxDB  “example_1”DB  “HelloWorld”/*****************************************************************************/

这种结构就充分说明了指令和数据并不区分,本来CALL指令用来在栈上保存指令,结果现在被用来保存数据了。

下面就是利用上述结构编写的汇编程序:

/*****************************************************************************/// example_8 nasm下的汇编ShellcodeSECTION .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/*****************************************************************************/

RunMsgBox中第一句pop ebx就将“user32.dll”的首地址保存在了ebx,这里注意与栈不同,后面的ebx地址是加而不是减。使用命令:

nasm -f win32 example_8.asm

编译为obj文件。然后使用VS的cl.exe,链接为exe:

cl example_8.obj libcmt.lib

运行exe,成功:

这里写图片描述
图34

下面我们在Immunity Debugger来看看:
这里写图片描述
图35

这一段就是完整的代码,可见,字符串数据全部被反汇编为指令了,上图中标出了三个字符串的结尾符。

标出了结尾符之后,问题也就来了,是的,空字节,又出现了空字节,而且这次更不好处理,因为我们只用了字符串的首地址。为了不出现空字节,我们定义字符串的时候不能加0x00结束符,但是使用字符串的时候又需要该结束符,而且,这样定义的字符串位于代码段,代码段是不可写的,也就是一旦定义,不可修改。所以,如果空字节会引起问题,就不要这样定义。使用直接压栈的方法反而容易处理。

使用nasm有个好处,就是可以直接编译为bin格式,即操作码,例如:

nasm -f bin -o example_8.bin example_8.asm

用HexEdit打开example_8.bin,如下:

这里写图片描述
图36

这样,可以简单的写个程序将bin文件写出为Shellcode,就不用再去Immunity Debugger一个字节一个字节的抠出来了。

0 0