我试图在IDA中找出一种方法,哪些导出是数据导出,哪些是实函数导出。
例如,让我们看一下Microsoft的msftedit.dll的导出条目:
虽然CreateTextServices
是真正的导出函数:
IID_IRichEditOle
是数据导出,而IDA未能意识到这一点,将数据作为代码插入:
有人知道区分这两者的可靠方法吗?帮助将不胜感激。
提前致谢。
最佳答案
对于每种导出,都没有完全可靠的方法来执行此操作。
每次导出仅在可执行文件中指定一个偏移量-从逻辑上讲,任何引用该可执行文件的其他代码都可以将其视为代码或数据。
正如您提到的,您几乎可以在所有情况下提出启发式方法来检测导出的类型,但是很容易提出对任何给定启发式方法都无效的反例。以您建议的规则为例:
The exported entry will be considered a valid exported function if there is a
ret
instruction in the function, and there are more than<min>
valid instructions, and IDA recognizes the function's calling convention.
假阴性:您可能具有使用tail call optimization并以
jmp
指令而不是ret
指令结尾的函数。任何短函数也将失败。可以将IDA混淆为不将代码视为函数的几种方式。误报:内存中可能有一个字符串,紧接着是
C3
或C2
,例如db 'BACKGAMMON0',0,0C3h
-从逻辑上讲,它可以作为带ret
但不带参数的有效11指令函数分解。当您认为导出可以在逻辑上同时视为代码和数据时,这些线会更加模糊:想象一下,将导出时的字节序列复制到动态分配的内存中(甚至可能在另一个进程中),以后再执行作为代码。
如果IDA认为是代码,则可能合理的建议是仅信任IDA并将导出视为代码。 IDA的很大一部分功能是自动猜测数据的逻辑类型,通常它非常擅长。如您所显示,有时是错误的。但是无论如何您都无法获得100%的准确性。您能做的最好的事情就是在假阴性和假阳性之间取得平衡。
该问题的不确定性证明:
导出是否将作为代码执行尚不确定。导出是否将被读取为数据也是不确定的。由于我们不能保证两者都是正确的,因此不可能区分看似模棱两可的情况。
证明:假设我们有一个oracle
A(P,I,E)
,如果程序P
(包括其所有依赖项)执行(或读取)导出E
(从P
执行过程中加载的任何DLL)并带有“input”(外部),则返回oracle 1状态)I
。否则,它返回0。让我们构造一个最小程序
Z(P,I,E)
,当且仅当E
返回0时,该程序才执行(或读取)导出A(P,I,E)
(已将其DLL加载到地址空间中)。现在考虑
Z(Z,I,E)
的结果:如果
Z(Z,I,E)
执行(或从中读取)export E
,则A(Z,I,E)
将返回1。但是Z(Z,I,E)
定义为不访问导出E
,除非A(Z,I,E)
返回0。这是矛盾的。如果
Z(Z,I,E)
不执行(或不读取)export E
,则A(Z,I,E)
将返回0。但是Z(Z,I,E)
定义为当E
返回0时将访问导出A(Z,I,E)
。这是一个矛盾。因此,我们最初对oracle
A(P,I,E)
存在的假设被证明是错误的。但是通过仪器可以做得更好...
根据您要解决的确切问题,您可以在运行时确定哪些导出是有效函数。
例如,您可以编写一个应用程序,将应用程序debugs进行分析,并将guard pages放置在每个包含您要 Hook 的导出的页面上。这意味着,每当页面被访问(执行/读取/写入)时,都会引发异常,调试器程序将获得控制权。
调试器可以检查程序上下文,以查看进行了哪种类型的访问以及它是否与导出有关。如果访问是尝试执行导出,则可以在将控制权返回给程序之前执行某些 Hook 功能。否则,它可能只是将控制权返回给程序。
在任何一种情况下,
PAGE_GUARD
修饰符在每次异常后都会被取消,因此您需要每次都将其放回原处。毫不奇怪,这会使您的程序的执行非常慢,因为对包含导出的任何页面的任何R/W/X访问都会导致昂贵的context switch -这很可能包括大多数指令的执行,而这些指令是您导出的函数,以及与它们无关的其他几个函数。
您可以对其他检测工具采用类似的方法,例如Pin。
请注意,您可能无法通过检测获得有关每个导出的用法的信息。这是因为您可能需要确定导致程序访问每个导出的所需输入/外部状态,以了解该导出是用作代码还是用作数据(如果有的话)。
还要注意,执行和读取(甚至是写入)访问都可能在同一导出上发生。
关于windows - PE-从功能导出中区分数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40338682/