当前位置:首页 >> 政史地 >>

专题6-二进制代码分析a2z


二进制代码分析
2012.3

关于
? 那些盗版、破解软件,那些外挂程序,都 是什么人、怎么做的,用的什么技术和方 法啊? ? 我和你一样好奇。 ? 本文向你解释他们怎么做的。 ? 虽然本文的示例程序一般从C源程序开始, 但是他们显然没有。 ? 事实上,他们直接拿二进制程序开刀。

From the very be

gin:文件格式
? 数据文件
– – – – – – – – 纯文本 格式文本 带指令的文本(word宏) 脚本文件 EXE,ELF,a.out 静态lib DLL,SO 驱动文件,modules in linux

? 程序文件

Windows的系统文件
? Exe、dll、sys ? 配置文件 C:\WINDOWS\system32\config\system C:\WINDOWS\system32\config\sam C:\WINDOWS\repair\sam ? Windows的系统文件de自我保护

内存、地址
? ? ? ? 物理内存 分段:CS DS ES SS FS GS 分页,页表,non-page 进程逻辑地址空间

物理内存
? 存储器分为CPU缓存(1/2/3级)、主存、外存(磁盘等)。主 机板上能够插放的物理内存条的个数和容量是有限制的。 ? PC机上许多设备拥有自己的设备内存,这些设备内存会 映射到PC机的物理内存地址上,读写这段物理地址其实 会访问设备内存。 ? Windows各系列支持的物理内存上限是不一样的,从2G 到64G不等。理论上32位CPU硬件上只能支持4G内存的 寻址,超过4G的内存只能靠其他技术来弥补。 ? 比如Windows Server/32企业版即可使用超过4G物理内存 (虽然单进程地址空间仍限制是4G)。 ? 物理内存分配的最小单位是页4K或4M(或者是其他值)。 8086开始支持的分段机制在i386之后被淡化。

32bit 4GB
? ? ? ? x86 i386 x86-64 IA-64 Itanium

? 32位地址 ? 4G地址空间

Windows内存划分
? 32位系统上进程地址空间是2^32=4G,范 围从0x0000 0000~0xFFFF FFFF。 ? 0x00000000-0x0000FFFF(0k-64k)为 NULL指针范围,如果访问该范围(以及其他 未经映射的页面)会报告非法访问。另外, DOS程序还使用这个区域。 ? 0x00010000-0x003FFFFF (64k-4M)为 DOS程序保留,在某些条件下可以读写。

Windows内存划分
? 0x00400000-0x7FFEFFFF(4M-2G)为独享用 户分区,这将近2G的空间是进程独享的。如果在 boot.ini上设置了/3G,这个区域的范围即从2G扩 大为3G:0x00010000-0xBFFE-FFFF。系统dll在 这个区域,比如是0x7xxxxxxx。 ? 0x80000000-0xFFFFFFFF这个空间是供操作系 统内核代码、设备驱动程序、设备I/O高速缓存、 非页面内存池的分配、进程目表和页表等使用。 这段地址各进程是可以共享的。 ? 如果在boot.ini上设置了/3G,这个区域的范围从 2G缩小为1G:0xC0000000-0xFFFFFFFF。

内存区域
? 区域指的是地址空间中的一片连续地址。区域的 必须是最小单位(一般是64k)的整数倍。区域的状 态有空闲、私有、映射、映像。 ? 进程可以用VirtualAlloc/ VirtualFree申请/删除区 域,这时候的区域状态是私有,但是还不可以存 取数据,因为还需要和物理内存关联。 ? 当exe或DLL文件被映射进了进程空间后,区域状 态变成映像;当一般数据文件被映射进了进程空 间后,区域状态变成映射。

页面属性
? 物理页面的访问属性指的是对页面进行的具体操作:可 读、可写、可执行。CPU一般认为可读就是可执行,操 作系统细分组合【备注行】。其中最后两个属性在运行 同一个程序的多个实例时非常有用,它使得程序可以共 享代码段和数据段。一般情况下,多个进程可以共享只 读或执行页面,如果要写的话,将会Copy页面到新的页 面(copy-on-write)。 属性PAGE_NOCACHE、PAGE_WRITECOMBINE是 开发设备驱动的时候需要的。 PAGE_GUARD属性,当往页面写入一个字节时,应用 程序会收到堆栈溢出通知,在线程堆栈时有用。

? ?

映射过程
? ? 进程地址空间的地址是虚拟地址,当取到指令时,需要把 虚拟地址转化为物理地址才能够存取数据。这个工作通过 页目和页表进行。 映射过程:逻辑地址高10位用来找到1024个页目项中的 一项,取出页表的物理地址后,利用中10位来得到页表项 的值,根据这个值得到物理页的地址,由于一页有4K大 小,利用低12位得到单元地址,这样就可以访问这个内存 单元了。 CPU的CR3寄存器会保存当前进程的页目物理地址。 当进程被创建时,同时需要创建页目和页表,一共需要 4.4M。在进程的空间中,0xC030 0000~0xC030 0FFF是 用来保存页目的4k空间。0xC000 0000~0xC03F FFFF是 用来保存页表的4M空间。也就是说程序里面访问这些地 址你是可以读取页目和页表的具体值的(要工作在内核方 式下)。

? ?

PT
?

交换文件
? 交换文件是存在硬盘上的系统文件,它的大小 可以在系统属性里面设置,它相当于物理内存 ,所以称为虚拟内存。它的大小是影响系统快 慢的关键因素之一,尤其是物理内存不多的情 况下。 分页内存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
?

EXE文件(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 mfc90.dll – WS2_32.dll / Winsock.dll

tasklist /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; return c; } main() { int s = f1(0x11223344,0x55667788); printf… }

jmp表
? ? ? ? ? ? ? ? ? ? ? ? ? @ILT+635(_bind@12): 00411280 jmp bind (411EF2h) @ILT+640(__msize_dbg): 00411285 jmp _msize_dbg (415320h) @ILT+645(__fcloseall): 0041128A jmp _fcloseall (416CA0h) ? @ILT+680(_OutputDebugStringA@4): 004112AD jmp OutputDebugStringA (42598Ah) @ILT+685(?f1@@YAHHH@Z): 004112B2 jmp f1 (411C20h) @ILT+690(_WriteFile@20): 004112B7 jmp WriteFile (425978h)

函数调用约定风格
? _cdecl 是C Declaration的缩写,C语言默认的函 数调用方法:所有参数从右到左依次入栈,参数 由调用者清除。 ? _stdcall 是Standard Call的缩写,是C++的标准调 用方式:所有参数从右到左依次入栈(调用类成 员时,最后一个入栈的是this指针)。参数由被调 用的函数在返回后清除,使用的指令是 retn X,X 表示参数占用的字节数。 ? _fastcall 是编译器指定的快速调用方式。由于大 多数的函数参数个数很少,使用堆栈传递比较费 时。因此_fastcall通常规定将前两个(或若干个 )参数由寄存器传递,其余参数还是通过堆栈传 递。不同编译器编译的程序规定的寄存器不同。 返回方式和_stdcall相当。

? _thiscall 是为了解决类成员调用中this指针传递而 规定的。_thiscall要求把this指针放在特定寄存器 中,该寄存器由编译器决定。VC使用ecx, Borland的C++编译器使用eax。返回方式和 _stdcall相当。 ? PASCAL 是Pascal语言的函数调用方式,也可以 在C/C++中使用,参数压栈顺序与前两者相反。 ? C中不加说明默认函数为_cdecl方式(C中也只能 用这种方式),C++也一样,但是默认的调用方 式可以在IDE环境中设置。

装载exe
? 装载一个exe文件时,系统不会将整个exe 文件和所有的DLL文件装载进物理内存中, 同时它也不会装载进页面文件中。相反, 它会建立文件映射,也就是利用exe本身当 作页面文件。系统将部分二进制代码装载 进内存,分配页面给它。
?

Exe\dll在一起:内存布局
? 系统DLL起始逻辑地址一般大于0x5* ? Copy-on-write机制

? 用OllyDbg查看布局

阅读exe代码
? 静态分析:IDA ? 动态调试:ollydbg

用IDA查看EXE/DLL
? 二进制、汇编、伪代码、调用图
? ? ? ? ? Section/segment 函数:导入和导出 起始地址 函数/代码调用关系图 伪代码:F5

IDA:汇编代码和流程图
?

P-code
? if ( v2 == 267 ) ? { ? if ( *(_DWORD *)(v1 + 116) > 0xEu ) ? { ? v3 = 0; ? v4 = *(_DWORD *)(v1 + 232) == 0; ? goto LABEL_10; ? } ? LABEL_5: ? v20 = 0; ? goto LABEL_11; ? } ? 【备注行】

Ollydbg(od)的使用
? 汇编/寄存器/栈/数据窗口 ? 内存地图 ? …

使用断点
? ? ? ? 在当前某行 在某地址、在某个地址范围 某个条件触发 当执行、读、写时

? 某个系统dll函数

演示bp bind
? 使用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, CREATE_SUSPENDED, NULL,NULL, &si, &pi);

? DWORD dw = ResumeThread(pi.hThread);

读写目标进程的数据和代码
? CreateProcess (CREATE_SUSPENDED) ? OpenProcess(PROCESS_CREATE_THR EAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, pi.dwProcessId); ? BOOL b = WriteProcessMemory(hp2, (char*)(tbase), “??", 2, &len2); ? ReadProcessMemory()

示例
?

在目标进程中创建线程
? CreateRemoteThread()

注入DLL
? 注入DLL是利用某种手段,让dll加载到目标 进程exe的地址空间,这样在dll代码中可以 直接访问exe整个4G地址空间中的代码和数 据。 ? 相比Read/WriteProcessMemory方便的多 ,因为exe中可以直接调用该dll中和函数, dll部分也可以调用exe部分的函数。

Dll注入技术
? DLL injection
代码 … injection.dll … exe本身的 数据和代码 main.cpp GetProcAddress() CreateRemoteThread() exe


user32.dll Kernel32..dll …

的 逻 辑 地 址 空 间

injection.cpp beginthread() asm { push … call 0x55aa } f.exe 0x55aa: mov … add …

(4G)

注入方法(1)AppInit_DLLs
? Windows Registry Editor Version 5.00 ? [HKEY_LOCAL_MACHINE\SOFTWARE\ Microsoft\Windows NT\CurrentVersion\Windows] ? "AppInit_DLLs"="c:\\mydll3.dll"
? 建立一个reg后缀名的文件,把如上内容放 进去。

演示
? 记事本+ws2_32.dll

有选择地驻留
? BOOL APIENTRY DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved) ? { ? char name[200]={0}; ? char *pn = name; ? DWORD dw = GetModuleFileName(0, pn, sizeof(name)); ? if (strstr(pn, “notepad") || strstr(pn, “wordpad")) ? ; ? else ? return FALSE; // 其他进程的话,直接不用加载了。 ? } ? 。。。

注入方法(2)针对某个exe进程
? HMODULE hKernel32 = GetModuleHandle("Kernel32"); ? laf = GetProcAddress(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

? 显示一个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中的函数

调用exe中的函数:f1() in exe
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int 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 eax,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))0x00413690; int s = f1(1,2); fprintf(f, "%d\n", s);

How to call f1 in dll: 汇编风格
? ? ? ? ? ? ? ? ? int f1=0x00413690; int s; _asm { push 2 push 1 call f1 mov s, eax } fprintf(f, "%d\n", 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过程,只把偏移地址压入堆栈 ,过程返回时用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 004136F5 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:[<&Common.?DelIdleCall>;

? int replace_funcall_at (byte* where, byte* faddr) ? { // 修正地址,当call/e8时 ? if (*(where-1)==0xe8) ? faddr = faddr-(int)(where+4); ? else ; ? // 需要先获取写权限 ? acquire_access(where, 4); ? *(DWORD*)where = DWORD(faddr); ? return 0; ? }

? replace_funcall_at ( (byte*)(0x004136F7+1), (byte*)myf1 );

修改exe代码示例:recvfrom
? 某个进程a使用recvfrom从网络接收udp报 文。现已有一报文,假装从网上来的,让a 接收到。。。

在a.exe
? 004xxxxx ? 004xxxxx ? 004xxxxx FF15 DCA94600 8BF8 83FF FF CALL DWORD PTR DS:[46A9DC] MOV EDI,EAX CMP EDI,-1

参考代码
? 仅供参考

Hack系统dll中的函数
? bind() in ws2_32.dll ? ? ? ? ? ? ? 71A2447E 90 NOP 71A2447F 90 NOP 71A24480 > 8BFF MOV EDI,EDI 71A24482 . 55 PUSH EBP 71A24483 . 8BEC MOV EBP,ESP 71A24485 . 51 PUSH ECX 71A24486 . 813D 5040A371 292CA271 CMP DWORD PTR DS:[71A34050],ws2_32.71A22C29 ; 入口地址 71A24490 . 56 PUSH ESI 71A24491 . 0F84 21480000 JE ws2_32.71A28CB8 71A24497 > E8 E5E1FFFF CALL ws2_32.71A22681 71A2449C . 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 = 0x68; // push ad_inhij1 int ad_inhij1; _asm { push lb_inhij1; pop ad_inhij1; } *(int*)(pb+1) = ad_inhij1; *(pb+5) = 0xc3; // ret

? _asm { ? lb_inhij1: ? pushad ? push [esp+28h] // sockaddr* ? call setsockopt_incr_port ? add esp, 4 ? popad ? // 在bind原来开始位置的6个字节的4条指令 ? mov edi,edi ? push ebp ? mov ebp,esp ? push ecx ? push addr_bind_add6 ? _emit 0xc3; // ret ? }

对抗代码逆向:花指令等
? ? ? ? ? 花指令 无效指令 垃圾指令 指令混淆

? 语法 vs. 语义

花/混淆指令举例
? main: ? jz Do_It ? jnz Do_It ? db 0E8h ? Do_It: ? invoke MessageBox, NULL, addr szText, addr szCaption, MB_OK ? invoke ExitProcess, 0 ? end main

? ? ? ? ? ? ? ? ?

:00401000 :00401002 :00401004 :00401009 :0040100C :00401011 :00401013 :00401018 :0040101A

7403 7501 E86A00681D 304000 6800304000 6A00 E80E000000 6A00 E801000000

je 00401005 jne 00401005 call 1DA81073 xor byte ptr [eax+00], al push 00403000 push 00000000 Call 00401026 push 00000000 Call 00401020

花/混淆指令举例
? ? ? ? call some_funcs db ?? ?? ?? add … 由于它默认call指令的返回地址是call指令 的下一条指令的地址,忽视了call指令调用 的子过程中对堆栈的修改,因此在子过程 返回后会继续解码,这种处理方法同样会 将无用数据解码成指令。

添加花指令工具
? Google(“随机花指令”)

? 演示

壳 packer
? 常见的压缩壳有UPX、ASPack和 PECompact等。 ? 常见的加密壳有ASProtect、Armadillo(穿 山甲)、EXECryptor、Themida、 VMProtect等。 ? 加壳过程通常会结合使用压缩和加密操作。 ? 当前加壳发展的一个趋势是虚拟机保护壳。

Upx演示
?

对抗代码逆向:代码虚拟化
? 虚拟机保护技术使用类似于Java的虚拟机 技术,就是把要执行的指令通过Java的虚 拟机JVM来解释字节码并执行。 ? VMProtect和ASProtect的SDK编程差不多 ,都是在编程时在语句里面插入一个标记 (Marker),然后在加壳处理时时,加壳程序 就会认出这些标记,并对标记区间内的代 码进行保护。

典型的虚拟机结构
?
VStartVM

VMDispacher

Bytecode

Handler1

Handler2

Handler3

带壳程序的运行特点
? 静态分析无效 // IDA ? 动态执行过程中分段解压缩(解密)执行

? 虚拟机保护下的

VMProtect
? ? ? ? ? ? ? ? ? ? ? ? ? #include <windows.h> #include <stdio.h> #include "VMProtectSDK.h“ main() { unsigned int x; x = rand(); VMProtectBegin("test--1"); x += 0x11223344; x *= 0xaabbccdd; VMProtectEnd(); printf("a=%d\n", x); return 0; }

脱壳 unpacker
? 常用的脱壳工具
– File Scanner 通用的脱壳工具 – ProcDump32 通用脱壳工具 – ASPack unpacker – ACProtect Stripper – UPX自带脱壳的命令 – Upxfix – UnPEPack用于脱PEPACK

Themida:4种保护宏
? Encode:解密出被保护的原始x86指令执 行完毕后马上又重新加密回去。 ? Clear:执行完毕后删除原有的80x86指令 ,下次需要再执行则要重新解密。 ? CodeReplace: ? VM:用虚拟机解释系统替换掉原有的x86 指令。

脱壳后代码

插件

虚拟机

加壳后代码

调试器进程

目标进程

Od插件:反反跟踪
? PhantOm.dll
? StrongOD.dll

中断、异常
? 外部中断interrupt,异步的,无法预测,软 件可以关中断,这样就眼不见心不烦了。 ? 由软件产生的中断如X86的“INT n”,程序有 意主动产生,这种称之为“陷阱”。 ? 与中断相似的机制称之为“异常”(exception) ,一般也是异步的,多半是由于“不小心”犯 了规才发生的。例如,div 0、缺页、非法 地址访问、调试中断等。

结构化异常处理(SEH)
? Structured Exception Handling ? 操作系统中的 EXCEPTION_REGISTRATION 结 构链表 ? 当异常发生时,系统遍历这个链表以便查找其中 的一个结构,询问是否同意处理该异常。异常处 理程序通过返回如ExceptionContinueExecution 表示它同意处理这个异常。 ? 异常回调函数也可以拒绝处理这个异常。此时, 系统会继续询问下一个结构。

SEHOP
? Structured Exception Handler Overwrite Protection(结构化异常处理覆盖保护) ? SEH攻击是指通过栈溢出或者其他漏洞, 使用精心构造的数据覆盖结构化异常处理 链表上面的某个节点或者多个节点,从而 控制EIP(控制程序执行流程)。而 SEHOP则是是微软针对这种攻击提出的一 种安全防护方案。

SEHOP效果
? SEHOP的保护是系统级别的,将更难绕过去。而 且不需要修改原有的应用程序,对性能的影响基 本可以忽略(因为只有在触发异常时才会触发 SEHOP保护逻辑)。而覆盖SEH进行攻击是在 /GS的保护出来以后,无法覆盖函数返回地址时 ,攻击者常用的技巧。 ? SEHOP方案终结了SEH覆盖攻击吗?NO!【备 注行】的基本思路是构造一个伪造的SEH链表, 从而欺骗SEH检测,达到绕过的目的。 ? 不过,作者也提到了在ASLR和DEP的都开启的 情况下,利用是非常困难的。

Assembly in VC

Basic sample: Buffer over flow
演示: ? 0. VC环境(in VS .NET) 1. C/ASM/CodeByte基础

2. 参数和堆栈stack
3. 函数调用的发生和返回

myf(int a, int b) { char buf[8]; puts("any str?"); gets(buf); … return 0; } main() { myf(0x11223344, 0xaabbccdd); return 0; }

4. gets()不小心导致堆栈 数据异常

对应的汇编代码
myf(0x11223344, 0xaabbccdd); 00411EDE push 0AABBCCDDh 00411EE3 push 11223344h 00411EE8 call @ILT+1305(_myf)(41151Eh) 00411EED add esp,8
调用函数后将 返回此地址

?

执行到puts()时的堆栈状况
myf(0x11223344, 0xaabbccdd); ? 0x0012FDEC 0x0012FDF0 0x0012FDF4 char buf[8]; 0x0012FDF8 0x0012FDFC Debug隔离带 0x0012FE00 ebp 0x0012FE04 return address 0x0012FE08 参数1 0x0012FE0C 参数2 0x0012FE10 0x0012FE14
cc cc cc cc dc ed 44 dd 00 cc cc cc cc fe 1e 33 cc 00 cc cc cc cc 12 41 22 bb 00 cc cc cc cc 00 00 11 aa 00 ???? ???? ???? ???? ??.. í.A. D3". ???? ....

输入16个字符,导致堆栈错误
buf本来8个字节, 给予20(+1)各字 ? 0x0012FDF0 符导致其覆盖了 ? 其后的13个字节, 0x0012FDF4 因此返回地址被 ? 0x0012FDF8 窜改

? ? 返回地址 ? (尾0)参数1 ? 参数2 ?

0x0012FDFC 0x0012FE00 0x0012FE04 0x0012FE08 0x0012FE0C

cc 61 61 61 61 61 00 dd

cc 61 61 61 61 61 33 cc

cc 61 61 61 61 61 22 bb

cc 61 61 61 61 61 11 aa

???? aaaa aaaa aaaa aaaa aaaa .3". ????

溢出会导致:
? 变量/数据被窜改(非期望的)
– 影响原来的设计功能

? 函数返回地址被窜改
– 返回另外一个地址 – 而那个地址已经被事先放好了准备好的代码

* 阅读材料
如何编写自己的缓冲区溢出利用程序.txt

利用BoF
?
程序的设计功能: 输入正确的口令后 做某项工作(否则重 复要求输入口令) 演示: 输入精心计划好的 字串打乱设计期望 的执行逻辑,从而 绕过某些口令

main() { char passwd[8] = {"2e4rfe"}; char yourpasswd[8] = {""}; 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 want return 0; }

Ready ? !

Try

Ha ha !

Pass !

gets(), scanf(), memcpy(), strcpy() etc
? sc_passwd\source1.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_6th.exe
– 绕过其口令保护

? sc_6th.exe
– 需要VC7的运行库 – 这个程序很小,因为它除了要个口令外,啥也 不做。该程序无任何不良操作

? Sc_6th.zip
– 含有对应的源程序 – 其保护口令可分析sc_6th.exe获得

利用堆栈执行某些代码
? SQL蠕虫
– 376(?)字节 – 完整的udp分组? – 如何溢出 – 如何执行 – 代码部分的分析 – http://www.smth.edu.cn/cgibin/bbs/bbs0an?path=%2Fgroups%2Fcomp% 2Efaq%2FVirus

Exploit example
? Buffer overflow 致堆栈数据被执行的例子

Exploit-1.1.zip

MS08-067
? 演示

dep
? NX “No eXecute”
– Windows 的保护机制 – Linux ?

Address space layout randomization
? Address space layout randomization (ASLR) is a computer security technique which involves randomly arranging the positions of key data areas, usually including the base of the executable and position of libraries, heap, and stack, in a process's address space.

代码安全:不能假设
? 不能相信用户的输入
– gets,scanf – http://192.168.85.131/scripts/..%c1%1c../winnt /system32/cmd.exe?/c+dir

? 不能假设用户操作按照你想象的正确顺序
– 输入法漏洞

? 不能假设你的二进制代码不被分析
– vredir.vxd – rc4代码分析 – 破解:序列号sn、激活key

版权保护手段
? 安装序列号
– 用户、授权

? 运行口令
– 仿exe压缩工具upx

? Key软盘
– 或需光盘

? 专门的硬件
–卡 – watchdog

破解举例
int do_you_have_key() { // input key or serial number reuturn 0; } main() { if (!do_you_have_key()) exit(-2); // do my work return 0; }

asm and code byte
? ? ? ? ? ? ? ? ? ? ? 22: main() 23: { 24: if (!do_you_have_key()) 00401050 E8 AB FF FF FF call do_you_have_key (401000h) 00401055 85 C0 test eax,eax 00401057 75 14 jne main+1Dh (40106Dh) 25: { 26: puts("invalid key"); 00401059 68 38 71 40 00 push offset string “inva?" (407138h) 0040105E E8 34 00 00 00 call puts (401097h) 27: exit(-2);

cracker方案
? jne ? je 75 14 68 38 ? 74 14 68 38 ? mov eax, 0x???????? / mov eax, 1 E8 AB FF FF FF 85 C0? B8 01 00 00 00
? __asm { mov eax, 0x?? nop int 0x21 …… }

74/75实例
? NetSuper21>fc /b NetSuper.exe NetSuper破解 版.exe 正在比较文件 NetSuper.exe 和 NETSUPER破解版 .EXE 00003503: 74 75 000038E8: 74 75 00007C12: 75 74 0000AF72: 74 75 0000AF89: 74 75
? NetSuper21>

示例:softice找sn
? 序列号是通用的版权保护方法 ? Softice是一个著名的Ring0调试工具

序列号SN的屏蔽方法举例
? 程序运行后首先询问序列号 1 ? 输入错误则报告并中止 2 ? 输入正确则继续 3
如 何 绕 过 序 列 号

1

2

3

sc_5th.exe .zip

? 如何绕过序列号 ? 分析exe程序

SN !

– 分析直接得到序列号,或者从分析得知序列号的结构特征 ,从而构造一个合法的序列号 – 修改exe程序判断和跳转指令,改变程序的判断和逻辑序列

? 大概会有类似下面的逻辑序列(可能还有多处) if (??) cmp ?? ?? goon()! je/jne ?? else call goon() stop()! ? call stop()

Source,Asm +
? 如果有部分对应源程序的话,EZ。 总结 把字节序列 "5f 5e 50 74 13" 中 74 改作 75, 即可实现 "je ??" 到 "jne ??" 的转换, 从而导致输入及时错误的序列号也能继续。 (此时, 输入正确的序列号反而不能进入, 但是如果改作eb即可无论正确与否都可继续) 演示 ? 如果没有源程序,SoftICE。
– 需要知识、经验、耐心、运气的结合 – 需要改动多处逻辑 – 基本上,很难

SoftICE
? author
– http://www.compuware.com/products/driverstudio/soft ice/

? 主要提示
– 开始->…->Start SoftICE – CTL+D、x、CTL+Shift – 符号表C:\WINNT\system32\drivers\Winice.dat
? ? ? ? ? EXP=c:\winnt\System32\kernel32.dll EXP=c:\winnt\System32\user32.dll;GetDlgItemText(A+W) EXP=d:\winnt\System32\gdi32.dll EXP=d:\winnt\System32\comctl32.dll EXP=c:\winnt\System32\ws2_32.dll

– 选择合适的断点(A+W)
? bpx GetDlgItemText/MessageBox

? 演示

值得注意的WIN32 API
? ? ? ? hmemcpy (in win9x) GetWindowText GetDlgItemText MessageBox

? Socket API
– send recv – bind linsten connect

? http://boer.yoll.com/wdb/

SoftICE等破解并不 能解决用密码学加 密算法加密的情况 +------------+ |读入Key并对 | |后半部分解 | |密,然后调 | |至后面执行 | +------------+ |加密的代码 | |部分 | +------------+
网络查询Softice 的使用帮助

Softice snapshot

反编译、反汇编
? SoftICE之外
– trw2000

? MASM、NASM ? 有一些工具,但是效果都很差; 但实际上,这个工作很难。
– REC - Reverse Engineering Compiler
? http://www.backerstreet.com/rec/rec.htm

– UnUpx、H(exv?)iew、W32Dasm
– http://directory.google.com/Top/Computers/Programming/
? /Disassemblers/ ? /Disassemblers/DOS_and_Windows/

? By the way
– http://www.china-askpro.com/

案例学习和分析:XP算号器
? Windows XP开始使用在线激活,而且使 用了ECC,但是有一款针对XP的序列号 生成器软件,能够生成具有在线激活能力 的XP序列号。(至少在早期确实如此) ? 查阅相关资料,分析
– 其破解原理? – 如何改进XP的机制以抵御这种攻击? – 这是ECC的缺陷吗? – 如何看待密码算法和应用方式在整个安全中 的地位?

总结和参考资料
? serial number、product key、register code等等的很多属于此类
– 破解属于破坏程序执行的设计逻辑顺序 – 有的程序在运行过程中的很多地方检查sn,而 不单是在开始安装/运行的时候,因此难于破解

? 用某种密码学算法加密的不属于此类
– 比如doc/zip的加密口令(?) – 破解这类使用字典攻击/蛮力攻击等手段,属于 破译密码算法

? Kan Xue Xue Yuan
– http://www.pediy.com/

作业与练习
? ? ? ? ? QQ加密外挂 “how do you do” “瀊 珯呞 UTl圎<2 [?1稘辵'妚?” “md1bGFyIHBhc3Npb24LCB3aGljaCBpc yBhIGx ”

? D-H

QQ服务器的功能
?

案例展示
? 某程序进程运行到地址0x11223344位置的 时候,eax中存放的是端口号,ebp中4字节 是一个字符串的地址,这个字符串是我们 要找的ip地址。 ? 该程序在执行期间,会很多次的经过这个 地方,每次都有不同的ip端口,希望能自动 获得并显示。

end & qa


相关文章:
数电课后习题答案
D.Y=(A+ B )A D 2.若在编码器中有 5 0 个编码对象,则要求输出二进制代码位 数为 A.5 B 位。 B.6 C.10 D.50 3.一个 16 选 1 的数据选择...
和二进制有关的那些事
《和二进制有关的那些事儿——计算机中的信息编码》教学设计【学习者分析】 本...如: ●●● 6 【活动设计意图】 专题知识的留白设计,旨在激起学生的好奇心和...
更多相关标签:
二进制代码 | 二进制颜色代码 | vb十进制转二进制代码 | 十进制转二进制代码 | 二进制代码转换器 | 二进制代码翻译 | 二进制分析工具 | 二进制文件分析工具 |