1、关于 那些盗版、破解软件,那些外挂程序,都是什么人、怎么做的,用的什么技术和方法啊? 我和你一样好奇。 本文向你解释他们怎么做的。 虽然本文的示例程序一般从C源程序开始,但是他们显然没有。 事实上,他们直接拿二进制程序开刀。From the very begin:文件格式 数据文件 纯文本 格式文本 带指令的文本(word宏) 脚本文件 程序文件 EXE,ELF,a.out 静态lib DLL,SO 驱动文件,modules in linuxWindows的系统文件 Exe、dll、sys 配置文件C:WINDOWSsystem32configsystemC:WINDOWSsystem32co
2、nfigsamC:WINDOWSrepairsam Windows的系统文件de自我保护内存、地址 物理内存 分段:CS DS ES SS FS GS 分页,页表,non-page 进程逻辑地址空间物理内存 存储器分为CPU缓存(1/2/3级)、主存、外存(磁盘等)。主机板上能够插放的物理内存条的个数和容量是有限制的。 PC机上许多设备拥有自己的设备内存,这些设备内存会映射到PC机的物理内存地址上,读写这段物理地址其实会访问设备内存。 Windows各系列支持的物理内存上限是不一样的,从2G到64G不等。理论上32位CPU硬件上只能支持4G内存的寻址,超过4G的内存只能靠其他技术来弥补。 比如
3、Windows Server/32企业版即可使用超过4G物理内存(虽然单进程地址空间仍限制是4G)。 物理内存分配的最小单位是页4K或4M(或者是其他值)。8086开始支持的分段机制在i386之后被淡化。32bit 4GB x86 i386 x86-64 IA-64 Itanium (安腾) 32位地址 4G地址空间Windows内存划分 32位系统上进程地址空间是232=4G,范围从0 x0000 00000 xFFFF FFFF。 0 x00000000-0 x0000FFFF(0k-64k)为NULL指针范围,如果访问该范围(以及其他未经映射的页面)会报告非法访问。另外,DOS程序还使用
4、这个区域。 0 x00010000-0 x003FFFFF (64k-4M)为DOS程序保留,在某些条件下可以读写。Windows内存划分 0 x00400000-0 x7FFEFFFF(4M-2G)为独享用户分区,这将近2G的空间是进程独享的。如果在boot.ini上设置了/3G,这个区域的范围即从2G扩大为3G:0 x00010000-0 xBFFE-FFFF。系统dll在这个区域,比如是0 x7xxxxxxx。 0 x80000000-0 xFFFFFFFF这个空间是供操作系统内核代码、设备驱动程序、设备I/O高速缓存、非页面内存池的分配、进程目表和页表等使用。这段地址各进程是可以共享的
5、。 如果在boot.ini上设置了/3G,这个区域的范围从2G缩小为1G:0 xC0000000-0 xFFFFFFFF。内存区域 区域指的是地址空间中的一片连续地址。区域的必须是最小单位(一般是64k)的整数倍。区域的状态有空闲、私有、映射、映像。 进程可以用VirtualAlloc/ VirtualFree申请/删除区域,这时候的区域状态是私有,但是还不可以存取数据,因为还需要和物理内存关联。 当exe或DLL文件被映射进了进程空间后,区域状态变成映像;当一般数据文件被映射进了进程空间后,区域状态变成映射。页面属性物理页面的访问属性指的是对页面进行的具体操作:可读、可写、可执行。CPU一般
6、认为可读就是可执行,操作系统细分组合【备注行】。其中最后两个属性在运行同一个程序的多个实例时非常有用,它使得程序可以共享代码段和数据段。一般情况下,多个进程可以共享只读或执行页面,如果要写的话,将会Copy页面到新的页面(copy-on-write)。属性PAGE_NOCACHE、PAGE_WRITECOMBINE是开发设备驱动的时候需要的。PAGE_GUARD属性,当往页面写入一个字节时,应用程序会收到堆栈溢出通知,在线程堆栈时有用。映射过程进程地址空间的地址是虚拟地址,当取到指令时,需要把虚拟地址转化为物理地址才能够存取数据。这个工作通过页目和页表进行。映射过程:逻辑地址高10位用来找到1
7、024个页目项中的一项,取出页表的物理地址后,利用中10位来得到页表项的值,根据这个值得到物理页的地址,由于一页有4K大小,利用低12位得到单元地址,这样就可以访问这个内存单元了。CPU的CR3寄存器会保存当前进程的页目物理地址。当进程被创建时,同时需要创建页目和页表,一共需要4.4M。在进程的空间中,0 xC030 00000 xC030 0FFF是用来保存页目的4k空间。0 xC000 00000 xC03F FFFF是用来保存页表的4M空间。也就是说程序里面访问这些地址你是可以读取页目和页表的具体值的(要工作在内核方式下)。PT 交换文件交换文件是存在硬盘上的系统文件,它的大小可以在系统
8、属性里面设置,它相当于物理内存,所以称为虚拟内存。它的大小是影响系统快慢的关键因素之一,尤其是物理内存不多的情况下。分页内存Paged Pool和非分页内存Nonpaged Pool区别:分页内存是指可以被交换到硬盘上的内存页,非分页内存是指不能被换出的内存页,即他只能存在于物理内存内,被交换到硬盘上。 代码、数据、堆栈 CS IP DS ES SS SP EIP ESP 访问非法地址寄存器 AL,AH,AX,EAX,RAX AX,BX,CX,DX,BP,SP,SI,DI CS,DS,SS,ES,FS,GS FLAGS,IP CR0,CR1,CR2,CR3 调试寄存器 测试寄存器 CRx EX
9、E文件(DLL也一样) exe文件有自己的格式,有若干节(section): .text用来放二进制代码(exe或dll); .data用来放各种全局数据。 .rsrc .rdata .idata观察EXE文件 用OllyDbg看节 用ida静态分析 入口地址 引用的dll函数库 函数名/地址Exe和dll 系统DLL kernel32.dll user32.dll ntdll.dll shell32.dll GDI32.dll OLE32.dll comctl32.dll , msvcr71.dll msvcr90.dll mfc42.dll mfc71.dll mfc80.dll mfc9
10、0.dll WS2_32.dll / Winsock.dlltasklist /m 观察重要的DLL 重要的dll函数 bind send recv connect hmemcpy (in win9x) GetWindowText GetDlgItemText MessageBox 用IDA查看系统DLL:导出函数Exe文件:visual studio角度 main.c main.exe 观察:汇编、机器码 观察:函数、地址 观察:局部变量和BP 观察:参数和堆栈 观察:函数返回时参数ESP调整用vc看函数调用过程 int f1(int a , int b) int c; c=a+b; ret
11、urn c; main() int s = f1(0 x11223344,0 x55667788); printf jmp表ILT+635(_bind12):ILT+635(_bind12):00411280 jmp bind (411EF2h) 00411280 jmp bind (411EF2h) ILT+640(_msize_dbg):ILT+640(_msize_dbg):00411285 jmp _msize_dbg (415320h) 00411285 jmp _msize_dbg (415320h) ILT+645(_fcloseall):ILT+645(_fcloseall):
12、0041128A jmp _fcloseall (416CA0h) 0041128A jmp _fcloseall (416CA0h) ILT+680(_OutputDebugStringA4):ILT+680(_OutputDebugStringA4):004112AD jmp OutputDebugStringA (42598Ah) 004112AD jmp OutputDebugStringA (42598Ah) ILT+685(?f1YAHHHZ):ILT+685(?f1YAHHHZ):004112B2 jmp f1 (411C20h) 004112B2 jmp f1 (411C20h
13、) ILT+690(_WriteFile20):ILT+690(_WriteFile20):004112B7 jmp WriteFile (425978h) 004112B7 jmp WriteFile (425978h) 函数调用约定风格 _cdecl 是C Declaration的缩写,C语言默认的函数调用方法:所有参数从右到左依次入栈,参数由调用者清除。 _stdcall 是Standard Call的缩写,是C+的标准调用方式:所有参数从右到左依次入栈(调用类成员时,最后一个入栈的是this指针)。参数由被调用的函数在返回后清除,使用的指令是 retn X,X表示参数占用的字节数。 _
14、fastcall 是编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。因此_fastcall通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同。返回方式和_stdcall相当。- _thiscall 是为了解决类成员调用中this指针传递而规定的。_thiscall要求把this指针放在特定寄存器中,该寄存器由编译器决定。VC使用ecx,Borland的C+编译器使用eax。返回方式和_stdcall相当。 PASCAL 是Pascal语言的函数调用方式,也可以在C/C+中使用,参数压栈顺序与前两者相反。 C
15、中不加说明默认函数为_cdecl方式(C中也只能用这种方式),C+也一样,但是默认的调用方式可以在IDE环境中设置。装载exe 装载一个exe文件时,系统不会将整个exe文件和所有的DLL文件装载进物理内存中,同时它也不会装载进页面文件中。相反,它会建立文件映射,也就是利用exe本身当作页面文件。系统将部分二进制代码装载进内存,分配页面给它。 Exedll在一起:内存布局 系统DLL起始逻辑地址一般大于0 x5* Copy-on-write机制 用OllyDbg查看布局阅读exe代码 静态分析:IDA 动态调试:ollydbg用IDA查看EXE/DLL 二进制、汇编、伪代码、调用图 Secti
16、on/segment 函数:导入和导出 起始地址 函数/代码调用关系图 伪代码:F5IDA:汇编代码和流程图 P-code if ( v2 = 267 ) if ( *(_DWORD *)(v1 + 116) 0 xEu ) v3 = 0; v4 = *(_DWORD *)(v1 + 232) = 0; goto LABEL_10; LABEL_5: v20 = 0; goto LABEL_11; 【备注行】Ollydbg(od)的使用 汇编/寄存器/栈/数据窗口 内存地图 使用断点 在当前某行 在某地址、在某个地址范围 某个条件触发 当执行、读、写时 某个系统dll函数演示bp bind 使
17、用bp bind 修改bind端口+1 在运行中:修改exe代码和数据 调试模式(DEBUG_PROCESS) SUSPENDED模式(CREATE_SUSPENDED)CreateProcess(CREATE_SUSPENDED)/ 准备参数STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory( &si, sizeof(si) );si.cb = sizeof(si);ZeroMemory( &pi, sizeof(pi) );/BOOL b = CreateProcess(targetexe, NULL, NULL, NULL, false, C
18、REATE_SUSPENDED, NULL,NULL, &si, &pi); DWORD dw = ResumeThread(pi.hThread);读写目标进程的数据和代码 CreateProcess (CREATE_SUSPENDED) OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, pi.dwProcessId); BOOL b = WriteProcessMemory(hp2, (char*)(tbase), “?, 2, &len2); ReadProcessMem
19、ory()示例 在目标进程中创建线程 CreateRemoteThread()注入DLL 注入DLL是利用某种手段,让dll加载到目标进程exe的地址空间,这样在dll代码中可以直接访问exe整个4G地址空间中的代码和数据。 相比Read/WriteProcessMemory方便的多,因为exe中可以直接调用该dll中和函数,dll部分也可以调用exe部分的函数。Dll注入技术 DLL injection exe本身的数据和代码injection.dlluser32.dllKernel32.dllexe的逻辑地址空间的逻辑地址空间(4G) 代码代码main.cpp GetProcAddress
20、() CreateRemoteThread()injection.cpp beginthread() asm push call 0 x55aa f.exe 0 x55aa: mov add 注入方法(1)AppInit_DLLs Windows Registry Editor Version 5.00 HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWindows AppInit_DLLs=c:mydll3.dll 建立一个reg后缀名的文件,把如上内容放进去。演示 记事本+ws2_32.dll有选择地驻留BOOL API
21、ENTRY DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)char name200=0;char *pn = name;DWORD dw = GetModuleFileName(0, pn, sizeof(name);if (strstr(pn, “notepad) | strstr(pn, “wordpad);elsereturn FALSE; / 其他进程的话,直接不用加载了。注入方法(2)针对某个exe进程 HMODULE hKernel32 = GetModuleHandle(Kernel32); laf = Ge
22、tProcAddress(hKernel32,LoadLibraryA), HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0,laf, fulldllremote, 0, &tid );switch( fdwReason ) case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH:in injected DLL 显示一个windows窗口 messagebox 用文件记录调试信息 fopen 显示一
23、个dos窗口以输出信息 printf writefile创建DOS窗口:AllocConsole() static HANDLE flog = 0, fcin = 0; if (!flog) BOOL b = AllocConsole();flog = GetStdHandle(STD_OUTPUT_HANDLE); fcin = GetStdHandle(STD_INPUT_HANDLE); WriteFile(flog, buf, len, 0, 0);调用dll中的函数 调用send()等windows标准api函数 调用exe所私有的dll中的函数 差不多等同于调用exe中的函数调用e
24、xe中的函数:f1() in exeint f1( int a, int b )00413690 55 push ebp 00413691 8B EC mov ebp,esp 00413693 81 EC C0 00 00 00 sub esp,0C0h 00413699 53 push ebx 0041369A 56 push esi 0041369B 57 push edi 0041369C 8D BD 40 FF FF FF lea edi,ebp-0C0h 004136A2 B9 30 00 00 00 mov ecx,30h 004136A7 B8 CC CC CC CC mov e
25、ax,0CCCCCCCCh 004136AC F3 AB rep stos dword ptr edi return a+b;004136AE 8B 45 08 mov eax,dword ptr a 004136B1 03 45 0C add eax,dword ptr b How to call f1 in dll: C风格int (*f1)(int, int);f1 = (int (*)(int, int)0 x00413690;int s = f1(1,2);fprintf(f, %dn, s);How to call f1 in dll: 汇编风格int f1=0 x00413690
26、;int s;_asm push 2push 1call f1mov s, eaxfprintf(f, %dn, s);修改exe代码字节指令 Exe(以及dll)的代码字节可以执行 但是不可以写。 更改以获取写权限 int acquire_access(void* where, int len, int flag=PAGE_EXECUTE_READWRITE) DWORD old;BOOL b = VirtualProtect(where, len, flag, &old);return b; Call/E8 vs. Call/FF15 call 一个near过程,只把偏移地址压入堆栈,过程
27、返回时用retn返回 call一个far过程,把偏移地址和段地址入栈,过程返回时用retf返回 在过程中的ret指令根据near和far的不同,分别编译成retn和 retf 以上是抄的网文。 关键是E8调用是用4个字节修正EIP(加法),FF15调用是把4个字节直接赋值给EIP。修改exe代码示例:call/e8 in exe.c int f1(int a, int b) return a+b; void Cmym3Dlg:OnBnClickedButton1() f1(1, 2); f1(1,2)汇编代码(VC调试模式)f1(1, 2); 004136F3 6A 02 push 2 004
28、136F5 6A 01 push 1 004136F7 E8 0D DF FF FF call f1 (411609h) 004136FC 83 C4 08 add esp,8 myf1() in dll.c int myf1(int a , int b) return a+b+3; 目标让exe中调用f1的地方改为调用myf1修改函数地址: 引号内/ 004136F7 E8 0D DF FF FF call f1 (411609h) / 00401001 FF15 28914000 CALL DS:; int replace_funcall_at (byte* where, byte* fa
29、ddr) / 修正地址,当call/e8时if (*(where-1)=0 xe8) faddr = faddr-(int)(where+4);else ;/ 需要先获取写权限acquire_access(where, 4);*(DWORD*)where = DWORD(faddr);return 0; replace_funcall_at (byte*)(0 x004136F7+1),(byte*)myf1);修改exe代码示例:recvfrom 某个进程a使用recvfrom从网络接收udp报文。现已有一报文,假装从网上来的,让a接收到。在a.exe 004xxxxx FF15 004xx
30、xxx FF15 DCA94600DCA94600 CALL DWORD PTR DS:46A9DC CALL DWORD PTR DS:46A9DC 004xxxxx 8BF8 MOV EDI,EAX004xxxxx 8BF8 MOV EDI,EAX 004xxxxx 83FF FF CMP EDI,-1004xxxxx 83FF FF CMP EDI,-1参考代码 仅供参考Hack系统dll中的函数bind() in ws2_32.dllbind() in ws2_32.dll71A2447E 90 NOP71A2447E 90 NOP71A2447F 90 NOP71A2447F 90
31、NOP71A24480 8BFF MOV EDI,EDI71A24480 8BFF MOV EDI,EDI71A24482 . 55 PUSH EBP71A24482 . 55 PUSH EBP71A24483 . 8BEC MOV EBP,ESP71A24483 . 8BEC MOV EBP,ESP71A24485 . 51 PUSH ECX71A24485 . 51 PUSH ECX71A24486 . 813D 5040A371 292CA271 CMP DWORD PTR 71A24486 . 813D 5040A371 292CA271 CMP DWORD PTR DS:71A340
32、50,ws2_32.71A22C29 ; DS:71A34050,ws2_32.71A22C29 ; 入口地址入口地址71A24490 . 56 PUSH ESI71A24490 . 56 PUSH ESI71A24491 . 0F84 21480000 JE ws2_32.71A28CB871A24491 . 0F84 21480000 JE ws2_32.71A28CB871A24497 E8 E5E1FFFF CALL ws2_32.71A2268171A24497 E8 E5E1FFFF CALL ws2_32.71A2268171A2449C . 85C0 TEST EAX,EAX7
33、1A2449C . 85C0 TEST EAX,EAX在注入的dll中 DWORD old; unsigned char* pb = (unsigned char*)bind; / ?! addr_bind_add6 = pb+6; BOOL b = VirtualProtect(void*)pb, 6, PAGE_EXECUTE_READWRITE, &old); *pb = 0 x68; / push ad_inhij1 int ad_inhij1; _asm push lb_inhij1;pop ad_inhij1; *(int*)(pb+1) = ad_inhij1; *(pb+5)
34、= 0 xc3; / ret _asm lb_inhij1:pushadpush esp+28h/ sockaddr*call setsockopt_incr_portadd esp, 4popad / 在bind原来开始位置的6个字节的4条指令mov edi,edipush ebpmov ebp,esppush ecxpush addr_bind_add6_emit 0 xc3; / ret对抗代码逆向:花指令等 花指令 无效指令 垃圾指令 指令混淆 语法 vs. 语义花/混淆指令举例 main: jz Do_It jnz Do_It db 0E8h Do_It: invoke Messag
35、eBox, NULL, addr szText, addr szCaption, MB_OK invoke ExitProcess, 0 end main :00401000 7403 je 00401005:00401000 7403 je 00401005 :00401002 7501 jne 00401005:00401002 7501 jne 00401005 :00401004 E86A00681D call 1DA81073:00401004 E86A00681D call 1DA81073 :00401009 304000 xor byte ptr eax+00, al:0040
36、1009 304000 xor byte ptr eax+00, al :0040100C 6800304000 push 00403000:0040100C 6800304000 push 00403000 :00401011 6A00 push 00000000:00401011 6A00 push 00000000 :00401013 E80E000000 Call 00401026:00401013 E80E000000 Call 00401026 :00401018 6A00 push 00000000:00401018 6A00 push 00000000 :0040101A E8
37、01000000 Call 00401020:0040101A E801000000 Call 00401020花/混淆指令举例 call some_funcs db ? ? ? add 由于它默认call指令的返回地址是call指令的下一条指令的地址,忽视了call指令调用的子过程中对堆栈的修改,因此在子过程返回后会继续解码,这种处理方法同样会将无用数据解码成指令。添加花指令工具 Google(“随机花指令”) 演示壳 packer 常见的压缩壳有UPX、ASPack和PECompact等。 常见的加密壳有ASProtect、Armadillo(穿山甲)、EXECryptor、Themida
38、、VMProtect等。 加壳过程通常会结合使用压缩和加密操作。 当前加壳发展的一个趋势是虚拟机保护壳。Upx演示 对抗代码逆向:代码虚拟化 虚拟机保护技术使用类似于Java的虚拟机技术,就是把要执行的指令通过Java的虚拟机JVM来解释字节码并执行。 VMProtect和ASProtect的SDK编程差不多,都是在编程时在语句里面插入一个标记(Marker),然后在加壳处理时时,加壳程序就会认出这些标记,并对标记区间内的代码进行保护。典型的虚拟机结构 VStartVMVMDispacherBytecodeHandler1Handler2Handler3带壳程序的运行特点 静态分析无效 / I
39、DA 动态执行过程中分段解压缩(解密)执行 虚拟机保护下的VMProtect#include #include #include VMProtectSDK.h“main()unsigned int x;x = rand();VMProtectBegin(test-1);x += 0 x11223344;x *= 0 xaabbccdd;VMProtectEnd(); printf(a=%dn, x);return 0;脱壳 unpacker 常用的脱壳工具 File Scanner 通用的脱壳工具 ProcDump32 通用脱壳工具 ASPack unpacker ACProtect Stri
40、pper UPX自带脱壳的命令 Upxfix UnPEPack用于脱PEPACKThemida:4种保护宏 Encode:解密出被保护的原始x86指令执行完毕后马上又重新加密回去。 Clear:执行完毕后删除原有的80 x86指令,下次需要再执行则要重新解密。 CodeReplace: VM:用虚拟机解释系统替换掉原有的x86指令。插件插件调试器进程调试器进程虚拟机虚拟机目标进程目标进程脱壳后代码脱壳后代码加壳后代码加壳后代码追踪追踪Od插件:反反跟踪 PhantOm.dll StrongOD.dll中断、异常 外部中断interrupt,异步的,无法预测,软件可以关中断,这样就眼不见心不烦了
41、。 由软件产生的中断如X86的“INT n”,程序有意主动产生,这种称之为“陷阱”。 与中断相似的机制称之为“异常”(exception),一般也是异步的,多半是由于“不小心”犯了规才发生的。例如,div 0、缺页、非法地址访问、调试中断等。结构化异常处理(SEH) Structured Exception Handling 操作系统中的 EXCEPTION_REGISTRATION 结构链表 当异常发生时,系统遍历这个链表以便查找其中的一个结构,询问是否同意处理该异常。异常处理程序通过返回如ExceptionContinueExecution 表示它同意处理这个异常。 异常回调函数也可以拒绝
42、处理这个异常。此时,系统会继续询问下一个结构。SEHOP Structured Exception Handler Overwrite Protection(结构化异常处理覆盖保护) SEH攻击是指通过栈溢出或者其他漏洞,使用精心构造的数据覆盖结构化异常处理链表上面的某个节点或者多个节点,从而控制EIP(控制程序执行流程)。而SEHOP则是是微软针对这种攻击提出的一种安全防护方案。SEHOP效果 SEHOP的保护是系统级别的,将更难绕过去。而且不需要修改原有的应用程序,对性能的影响基本可以忽略(因为只有在触发异常时才会触发SEHOP保护逻辑)。而覆盖SEH进行攻击是在/GS的保护出来以后,无法
43、覆盖函数返回地址时,攻击者常用的技巧。 SEHOP方案终结了SEH覆盖攻击吗?NO!【备注行】的基本思路是构造一个伪造的SEH链表,从而欺骗SEH检测,达到绕过的目的。 不过,作者也提到了在ASLR和DEP的都开启的情况下,利用是非常困难的。Basic sample:Buffer over flow myf(int a, int b)char buf8;puts(any str?);gets(buf);return 0;main()myf(0 x11223344, 0 xaabbccdd);return 0;演示:0. VC环境(in VS .NET)1. C/ASM/CodeByte基础2.
44、 参数和堆栈stack3. 函数调用的发生和返回4. gets()不小心导致堆栈数据异常对应的汇编代码 myf(0 x11223344, 0 xaabbccdd);00411EDE push 0AABBCCDDh 00411EE3 push 11223344h 00411EE8 call ILT+1305(_myf)(41151Eh) 00411EED add esp,8调用函数后将返回此地址执行到puts()时的堆栈状况 0 x0012FDEC0 x0012FDEC0 x0012FDF0 cc cc cc cc 0 x0012FDF0 cc cc cc cc 0 x0012FDF40 x00
45、12FDF4 cc cc cc cc cc cc cc cc 0 x0012FDF8 cc cc cc cc 0 x0012FDF8 cc cc cc cc 0 x0012FDFC cc cc cc cc 0 x0012FDFC cc cc cc cc 0 x0012FE00 dc fe 12 00 .0 x0012FE00 dc fe 12 00 .0 x0012FE04 ed 1e 41 00 .A.0 x0012FE04 ed 1e 41 00 .A.0 x0012FE08 44 33 22 11 D3.0 x0012FE08 44 33 22 11 D3.0 x0012FE0C dd
46、cc bb aa 0 x0012FE0C dd cc bb aa 0 x0012FE10 00 00 00 00 .0 x0012FE10 00 00 00 00 .0 x0012FE140 x0012FE14myf(0 x11223344, 0 xaabbccdd);char buf8;Debug隔离带ebpreturn address参数1参数2输入16个字符,导致堆栈错误 0 x0012FDF0 cc cc cc cc 0 x0012FDF4 61 61 61 6161 61 61 61 aaaa 0 x0012FDF8 61 61 61 6161 61 61 61 aaaa 0 x00
47、12FDFC 61 61 61 61 aaaa 0 x0012FE00 61 61 61 61 aaaa 0 x0012FE04 61 61 61 61 aaaa 0 x0012FE08 00 33 22 11 .3. 0 x0012FE0C dd cc bb aa buf本来8个字节,给予20(+1)各字符导致其覆盖了其后的13个字节,因此返回地址被窜改返回地址(尾0)参数1参数2溢出会导致: 变量/数据被窜改(非期望的) 影响原来的设计功能 函数返回地址被窜改 返回另外一个地址 而那个地址已经被事先放好了准备好的代码* 阅读材料如何编写自己的缓冲区溢出利用程序.txt利用BoF main(
48、)char passwd8 = 2e4rfe;char yourpasswd8 = ;again:puts(please input passwd?);gets(yourpasswd);if (strcmp(yourpasswd, passwd)= =0)goto ok;puts(passwd error);goto again;exit(-2);ok:puts(correct!);/ do work you wantreturn 0;程序的设计功能:程序的设计功能:输入正确的口令后做某项工作(否则重复要求输入口令)演示:演示:输入精心计划好的字串打乱设计期望的执行逻辑,从而绕过某些口令Rea
49、dy ? !TryHa ha !Pass !gets(), scanf(), memcpy(), strcpy() etc sc_passwdsource1.cpp(12): warning C4996: gets: This function or variable may be unsafe. Consider using gets_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.buffer overflows in the heap练习 分析 sc_6
50、th.exe 绕过其口令保护 sc_6th.exe 需要VC7的运行库 这个程序很小,因为它除了要个口令外,啥也不做。该程序无任何不良操作 Sc_6th.zip 含有对应的源程序 其保护口令可分析sc_6th.exe获得利用堆栈执行某些代码 SQL蠕虫 376(?)字节 完整的udp分组? 如何溢出 如何执行 代码部分的分析 http:/ example Buffer overflow致堆栈数据被执行的例子 Exploit-1.1.zipMS08-067 演示dep NX “No eXecute” Windows 的保护机制 Linux ?Address space layout random