PE结构->【输入表】Import【上】

本文介绍了PE文件中的导入函数概念,通过实例分析hello.exe如何调用USER32.DLL中的MessageBox函数。通过反编译工具,观察函数调用的汇编代码,探讨了从VA转换到物理偏移地址的过程,揭示了函数地址的查找步骤,为下一部分深入理解输入表奠定了基础。

使用工具:PEinfo.exe, hello.exe,UE

输入函数

在代码分析或编程中经常遇到“输入函数(Import Functions,也称导入函数)”的概念。
这里我们就来解释下,输入函数就是被程序调用但其执行代码又不在程序中的函数,这些函数的代码位于相关的DLL 文件中,在调用者程序中只保留相关的函数信息(如函数名、DLL 文件名等)就可以。

这里写图片描述

以上是咱这次实验的小青蛙哈~灰常简单的一个小程序,如图双击程序只显示一个对话窗口,然后就结束~试验用小程序,我们尽量的将内部的结构删减,调试起来才方便些。
我们这次体验的目的就是想靠所学的知识,试图来找到MessageBox 在内存中的地址。

注:MessageBox 是来自于USER32.DLL 动态链接库里的一个函数,我们通过对PE 文件的静态反编译分析来观察hello.exe 这个试验品是如何定位和调用MessageBox 这个在“异乡”的函数哈。

MessageBox 有两个版本,一个是MessageBoxA 还有一个是MessageBoxW 分别带便ASCII码形式和UNICODE~历史故事了~)

体验开始:
1. 我们用曾经号称为屠龙刀的W32DAM 对hello.exe进行反编译,如图:
这里写图片描述

我们可以看到这个程序只有两个导入模块(Import Module),分别导入来自两个动态链接库(USER32.DLL和KERNEL32.DLL)的若干函数。

我们还清晰可见,咱要跟踪的MessageBoxA 就在USER32.DLL 中,这里程序还自动给我们定位了它的虚拟地址:2A2DC,但我们不要用这个。

我们通过W32DASM 的查找功能找出MessageBox 这个函数代码的位置,并试图查看他的汇编跳转~

这里写图片描述
各位看官看到了吧?push xxxx push xxxx push xxxx push xxxx 之后再来一个Call xxxx ……

没错,这就是调用函数的一个标准形式。每个push 其实就是将所要调用的函数需要的参数入栈

int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType // style of message box );

由定义可见MessageBox 函数共有四个参数,因此我们四次push xxxx 分别将参数按照STDCALL 的方式入栈之后,就可以CALL MessageBox 这个函数了。

好,既然是CALL 我们的目标函数了,通过反汇编我们就可以观察到它的地址是:[0042A2AC],难道就这么简单?

那我们就直接把程序往下拉,试图找找这个 42A2AC 的地址吧~
可是…… ……

这里写图片描述

我们悲剧的发觉,程序压根还没到 42A2AC 这地方,到了421FF8 就结束了!!什么情况呢?
没错,这是一个VA 哈

需要根据VA换算成实际地址,42A2AC 落在了 .idata区块中,请看下图:

这里写图片描述

我们看到,咱的42A2AC 地址加载咱的2A000 和 2B000 之间(改程序VC编写,映像基地址为400000打头哦~),因此我们可以将该地址定位到改程序位于.idata 区块内。

该区块的VA 起始地址为42A000,因此42A2AC – 42A000 = 2AC,raw data offs 跟我们说该区块的物理地址是28000,因此42A2AC 这个VA 所对应的物理偏移地址就是 28000 + (2A2AC-2A000 )= 282AC

咱用UE 打开看下282AC 这偏移地址上有啥东西……

这里写图片描述

282AC 这个地址上存放着 DCA20200 这个数据,翻译成ASCII 码也是莫名其妙的说~

但我们把DCA20200 当成一个DWORD 类型的数据来读的话我们得到数据 0002A2DC(还记得大端与小端吧)

慢着,是不是很熟悉,又是2A****开头,跟咱之前的地址是不是差不多?
那好,我们又按照刚才的方法转化为偏移地址试试,转化后得到的偏移地址是:282DC,【计算方式:28000+(2a2dc-2a000)=282DC】,咱再看看282DC 里边有啥神秘的东西吧?

这里写图片描述

哈哈,看到奇迹了吗?从282DC 地址读起,ASCII 码对应的值是MessageBoxA.USER32.dll

但根本问题我们还是没能解决:MessageBox 的地址是?其实在这里我们还不能帮大家解决这个问题,因为我们缺乏对输入表的深入理解。
所以我们期待吧,下节课将揭开输入表的神秘面纱……

Error: Error: Parse error on line 3: ...--> C[subprocess.run('video_detection2.p -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS' graph TD; A[video_detection_main] --> B[run_script]; B --> C[subprocess.run('video_detection2.py')]; A --> D[window.destroy]; subgraph video_detection2.py E[selected_video_path = None]; F[label_text = None]; G[cap = None]; H[GUI设计]; I[upload_video(canvas)]; J[return_main()]; K[video_detection()]; L[创建功能按钮]; H --> M[tk.Tk() - 创建主窗口]; H --> N[设置窗口大小]; H --> O[创建背景画布]; H --> P[加载背景图像]; H --> Q[在背景画布上绘制背景图像]; I --> R[filedialog.askopenfilename() - 选择视频文件]; I --> S[cv2.VideoCapture() - 打开视频文件]; I --> T[读取视频的第一帧]; I --> U[将OpenCV的BGR图像转换为RGB图像]; I --> V[将图像转换为PIL格式]; I --> W[将PIL图像转换为Tkinter兼容的图片]; I --> X[在画布上显示图像]; I --> Y[使用after方法更新画布]; J --> Z[subprocess.run('EfficientNet_uI_main.py')]; J --> AA[window.destroy]; K --> AB[cap.release() - 关闭上传视频正在播放的视频]; K --> AC[messagebox.showerror - 提示请先上传视频]; K --> AD[获取上传的视频文件名称]; K --> AE[获取E:\\ch_PP-OCRv3\\output文件夹中的所有视频文件]; K --> AF[检查是否有匹配的视频文件]; K --> AG[播放匹配的视频文件]; K --> AH[创建一个新窗口]; K --> AI[创建一个画布用于在新窗口中显示视频]; K --> AJ[在新窗口的画布上播放检测完的视频]; K --> AK[释放视频流]; K --> AL[弹出错误消息框]; L --> AM[创建一个大的画布区域]; L --> AN[创建按钮并放置在主窗口上]; L --> AO[将按钮放置在主窗口上]; end
最新发布
03-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值