Archive for the ‘技术’ Category

一个HelloWorld

VS2003 Debug配置编译了一个HelloWorld程序,主要代码如下:
int main()
{
 printf("Hello, world!\n");
 return 0;
}

用OD调试来学习一下它的运行机理。OD载入,程序停在如下位置:
00411339 > $ /E9 F2080000   jmp     mainCRTStartup

用LordPE查看下PE文件,发现镜像基址:00400000,入口点:00011339,00400000+00011339=00411339看来OD停在了入口点。

入口点jmp mainCRTStartup以及mainCRTStartup很明显是由编译器生成的。单步跟进mainCRTStartup或者在IDA中查看mainCRTStartup可以看到,在调用用户代码前后它都做了很多工作。
用户代码的调用点如下:
.text:00411D9B                 call    j__main

j_main也是由编译器生成的一小段存根代码,如下:
.text:004113BB ; int __cdecl j__main()
.text:004113BB j__main         proc near
.text:004113BB                 jmp     _main
.text:004113BB j__main         endp

为什么会这样?应该是库代码的框架是确定的,已经生成了obj?lib?or dll?但是用户代码的位置在链接前是不确定的(因为在不同的obj模块),通过这种存根的方法就能解决问题。

库代码和用户代码最终都被链接合并到了同一个exe文件中,如果是exe和dll之间的调用关系又该如何呢?
首先必须要知道要使用哪个dll的哪个函数,然后加载dll获取函数的地址,最后call或者jmp到函数中去。
PE的文件格式已经解决了如上问题。数据目录中的输入表目录指示了要使用哪个dll、该dll中有哪些导出函数以及在哪个位置保存这些导出函数的地址(IAT)。

HelloWorld.exe的输入表如图:

注意其FirstThunk的RVA:0002A17C,和数据目录的IAT RVA一致。打开IAT也可以发现其大小为4*62(kernel32.dll中有62个导出函数)用于保存函数地址。Windows Loader在加载dll的时候会负责正确地填充。

这样一来,可以说PE文件已经准备好了一切,调用dll变得简单call or jmp [IAT中对应函数的地址的偏移]。但这里依然有两种方式可选,一种是高效率的call [],另一种是低效率的存根方法(call 存根; 存根: jmp [];)。

IDA中可以发现类似如下代码:
.text:00411C79                 call    ds:__imp__GetVersionExA@4 ; GetVersionExA(x)
.text:004112D0 ; [00000005 BYTES: COLLAPSED FUNCTION GetVersionExA(x). PRESS KEYPAD "+" TO EXPAND]

它们分别对应着前面提到的两种选择,可见对一个导出函数的调用,编译器生成了两种可选方案,只是HelloWorld中最终没有发现有调用.text:004112D0处的代码。
虽然编译器生成了两种可选方案,但是可以对输入的dll导出函数加上__desclspec(dllexport)修饰符,就能在调用时使用高效率的方案。

main中的代码没有什么好解释的,提一下在main恢复堆栈后切换栈帧前,有如下代码:
.text:00411A60                 add     esp, 0C0h
.text:00411A66                 cmp     ebp, esp
.text:00411A68                 call    j___RTC_CheckEsp
.text:00411A6D                 mov     esp, ebp
.text:00411A6F                 pop     ebp
很明显j___RTC_CheckEsp堆栈平衡检查,但好像与securty cookie不同,并不会影响缓冲区溢出漏洞。

.net反编译

Invalid number of data directories in NT header

Reflector Error:Module '…' contains zero or multiple module definitions.(没彻底明白怎么改,所以失败了,::>_<::)

bochs

[科普]在bochs虚拟机中安装WindowsXP

Bochs 仿真软件

用Bochs调试NTLDR

bochs中查看段寄存器使用sreg命令!

32bit Or 64bit

一直比较困惑跨平台以及跨32bit/64bit边界的编程问题,主要是基本数据类型的sizeof大小问题。

比较确定的是(unsigned) char/(unsigned) short基本都是1byte/2byte。虽然int、long都是内置类型,但归根结底还是得看编译器的实现:32bit下一般都是4byte,64bit下就可能有多种情况了(44、48、88等)。但无论怎样编译器都知道它们的确切大小,有问题还是求助编译器吧。

32bit/64bit最大的区别就是指针大小,肯定是4byte和8byte了,因此Windows SDK的头文件通过是否定义了_WIN64宏来确定INT_PTR等自定义PTR类型的大小(_int64 or int)。

如何跨平台,当然是宏和typedef了。typedef时加上类型名称及位数,这样清晰明了,如typedef unsigned char uint8等。至于typedef unsigned int是uint32还是uint64估计还得看具体的环境了。

附上一篇参考资料:http://blog.csdn.net/tangl_99/article/details/1963762

跨平台C/C++数据类型定义

一个CrackMe

CrackMe地址:http://bbs.pediy.com/showthread.php?t=139622

PEiD查壳:

 

 

 

 

 

 

 

 

ESP定律脱壳:pushad过后,esp为0x12FF96,此处下硬件断点(Command中输入hr 12FF96,并在调试/硬件断点中查看)。

 

 

 

 

 

F9运行到断点,发现0x40510B处jmp 0x401000,即为OEP。来到0x401000处发现乱码,右键--->分析/分析代码即可。

设消息断点:删除硬件断点,F9让程序运行起来。菜单--->查看/窗口,找到“确定”按钮,右键--->设消息断点,设置WM_LBUTTONUP的消息断点。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

输入帐号和密码并“确定”,程序断在系统领空,此时无法使用Ctrl+F9返回或Alt+F9返回到用户领空,Alt+M为CrackMe的整个.text代码段下内存访问断点,再F9就会停在消息处理例程(乱码则右键--->分析/分析代码)。

Read more

无觅相关文章插件,快速提升流量