作者:潇潇沐林风_921 | 来源:互联网 | 2023-01-13 09:14
为感谢在上1版中做出辛勤回答者,将分数结算给“有容乃大,无欲则刚”和“每天学VC,补充你我的维C”。再做一版以给高手们加分。题目:我要取出DLL中的所有输出函数名的列表(包括地址,最好还有参数
为感谢在上1版中做出辛勤回答者,将分数结算给“有容乃大,无欲则刚”和“每天学VC,补充你我的维C”。
再做一版以给高手们加分。题目:
我要取出DLL中的所有输出函数名的列表(包括地址,最好还有参数类型列表)。
不谈COM类型的DLL,只是基本的动态库。
已经问了很多人,几乎一般的高手都被难倒了。
用ASM可能行不通了,因为只能查根据调用者的push次数来查。
但是我不能找到任意一个动态库的调用者。
但是PE(Portable Executable)好象没有记录“参数类型列表”
如有答对者给N00分,不惜!!!!
73 个解决方案
好象VC在Debug版编译时记录了,“参数类型列表”,但是不知道记在哪里了。
坐在炕头上,反复研究上一版中的答案。
发现property1(路标) 的答案最接近。
CALLBACK property1(路标) ( ) 回来加分。
其中GetExportDirectory和GetNtHeaders代码不全。
请重新“编译”一下。
喝口小米粥,看看老毛子的程序,写得真精!!
(就是看不懂毛文)
你的问题我早就注意到了,用DumpBin的缺陷就是无法得知参数,而就我看事实上你不可能得到dll输出函数的参数列表。
举例说明:我曾经参与过用驱动程序拦截上层API的项目,当时遇到的最大问题就是面对微软未公开的API,我们只能拦截到,却根本无法了解它们参数的含义,到后来也没办法解决。
当然,我算不上高手,对Dll很多地方并没有深入研究过,如果你真的找到了答案,希望能共享出来帮助大家,谢谢~
#include
#define MakePtr(base, offset) ((LPSTR)(base) + offset)
//@//////////////////////////////////////////////////////////////////////////
// §¤§Ý§à§Ò§Ñ§Ý§î§ß§í§Ö §á§Ö§â§Ö§Þ§Ö§ß§ß§í§Ö
static BOOL g_bUnicodeOS = FALSE;
static HMODULE g_hModuleUnicows = NULL;
static LPWORD g_pdwOrd = NULL;
static LPDWORD g_pdwAddrs = NULL;
static LPDWORD g_pdwNames = NULL;
static DWORD g_dwNames = 0;
//@//////////////////////////////////////////////////////////////////////////
// §£§ã§á§à§Þ§à§Ô§Ñ§ä§Ö§Ý§î§ß§Ñ§ñ §æ§å§ß§Ü§è§Ú§ñ, §Ó§à§Ù§Ó§â§Ñ§ë§Ñ§Ö§ä §Ñ§Õ§â§Ö§ã §æ§å§ß§Ü§è§Ú§Ú §Ú§Ù unicows.dll
// §ã §å§Ü§Ñ§Ù§Ñ§ß§ß§í§Þ §Ú§Þ§Ö§ß§Ö§Þ, §Ö§ã§Ý§Ú §ä§Ñ§Ü§Ñ§ñ §Ú§Þ§Ö§Ö§ä§ã§ñ
static LPDWORD GetFunctionAddress(LPCSTR azName)
{
DWORD dwName = 0;
while (dwName < g_dwNames)
{
if (0 == ::lstrcmpiA(MakePtr( g_hModuleUnicows, g_pdwNames[dwName]), azName))
return (LPDWORD)MakePtr(g_hModuleUnicows, g_pdwAddrs[g_pdwOrd[dwName]]);
dwName ++;
}
return NULL;
}
BOOL _UnicowsInit(LPCSTR szLib)
{
/* int i = ::GetVersion();
if (0 == (0x80000000 & ::GetVersion()))
{
// WinNT/2k/XP: §´§å§ä §ß§Ñ§Þ §Õ§Ö§Ý§Ñ§ä§î §ß§Ö§é§Ö§Ô§à
g_bUnicodeOS = TRUE;
return ::SetLastError(0), TRUE;
} */
g_hModuleUnicows = ::LoadLibraryA(szLib);
if (!g_hModuleUnicows)
return FALSE; // §°§ê§Ú§Ò§Ü§Ñ §á§â§Ú §Ù§Ñ§Ô§â§å§Ù§Ü§Ö Unicows.dll
// §¯§Ñ§ç§à§Õ§Ú§Þ §ä§Ñ§Ò§Ý§Ú§è§å §ï§Ü§ã§á§à§â§ä§Ñ
PIMAGE_DOS_HEADER pDosHeader = PIMAGE_DOS_HEADER(g_hModuleUnicows);
if (::IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER))
|| IMAGE_DOS_SIGNATURE != pDosHeader->e_magic)
return ::SetLastError(ERROR_INVALID_PARAMETER), FALSE;
PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)
MakePtr(g_hModuleUnicows, pDosHeader->e_lfanew);
if (::IsBadReadPtr(pNTHeaders, sizeof(IMAGE_NT_HEADERS))
|| IMAGE_NT_SIGNATURE != pNTHeaders->Signature)
return ::SetLastError(ERROR_INVALID_PARAMETER), FALSE;
IMAGE_DATA_DIRECTORY& expDir =
pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY pExpDir = (PIMAGE_EXPORT_DIRECTORY )
MakePtr(g_hModuleUnicows, expDir.VirtualAddress);
// §©§Ñ§á§à§ß§Ú§Þ§Ñ§Ö§Þ §ä§Ñ§Ò§Ý§Ú§è§å §Ú§Þ§Ö§ß §Ú §Ñ§Õ§â§Ö§ã§à§Ó
g_pdwOrd = (LPWORD)MakePtr(g_hModuleUnicows, pExpDir->AddressOfNameOrdinals);
g_pdwNames = (LPDWORD)MakePtr(g_hModuleUnicows, pExpDir->AddressOfNames);
g_pdwAddrs = (LPDWORD)MakePtr(g_hModuleUnicows, pExpDir->AddressOfFunctions);
g_dwNames = pExpDir->NumberOfNames;
return TRUE;
}
static LPCSTR GetNameFromOrdinal(HMODULE hModule,DWORD dwOrdinal)
{
if (!hModule)
return FALSE; // §¯§Ö§ä §ä§Ñ§Ü§à§Ô§à §Þ§à§Õ§å§Ý§ñ
// §¯§Ñ§ç§à§Õ§Ú§Þ §ä§Ñ§Ò§Ý§Ú§è§å §ï§Ü§ã§á§à§â§ä§Ñ
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)(hModule);
if (::IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER))
|| IMAGE_DOS_SIGNATURE != pDosHeader->e_magic)
return ::SetLastError(ERROR_INVALID_PARAMETER), FALSE;
PIMAGE_NT_HEADERS pNTHeaders =(PIMAGE_NT_HEADERS)
MakePtr( hModule, pDosHeader->e_lfanew);
if (::IsBadReadPtr(pNTHeaders, sizeof(IMAGE_NT_HEADERS))
|| IMAGE_NT_SIGNATURE != pNTHeaders->Signature)
return ::SetLastError(ERROR_INVALID_PARAMETER), FALSE;
IMAGE_DATA_DIRECTORY& expDir =
pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY pExpDir = (PIMAGE_EXPORT_DIRECTORY)
MakePtr( hModule, expDir.VirtualAddress);
LPWORD pdwOrd = (LPWORD)MakePtr( hModule, pExpDir->AddressOfNameOrdinals);
LPDWORD pdwNames = (LPDWORD)MakePtr(hModule, pExpDir->AddressOfNames);
dwOrdinal -= pExpDir->Base;
g_dwNames = pExpDir->NumberOfNames;
for (DWORD iName = 0; iName < pExpDir->NumberOfNames; iName++)
{
// §±§â§à§Ó§Ö§â§ñ§Ö§Þ §Ó§ã§Ö §ß§à§Þ§Ö§â§Ñ §á§à §á§à§â§ñ§Õ§Ü§å
if (dwOrdinal == pdwOrd[iName])
return MakePtr(hModule, pdwNames[iName]);
}/**/
return NULL;
}
int main(int,char**)
{
if(!_UnicowsInit("C:\\Test.dll"))
return -1;
LPCSTR szName = GetNameFromOrdinal(g_hModuleUnicows,1);
LPDWORD pTest = GetFunctionAddress(szName);
__asm
{
call pTest
}
szName = GetNameFromOrdinal(g_hModuleUnicows,2);
pTest = GetFunctionAddress(szName);
int nOffset= g_dwNames*sizeof(LONG);
__asm
{
push g_dwNames
push szName
call pTest
add esp,nOffset
}
_UnicowsRebindImports(g_hModuleUnicows);
return 0;
}
Text1.cpp刚起步,main是我写的。
其他抄老冒子的,乱码都是毛文。
我也看不懂。
http://www.rsdn.ru/archive/vc/issues/pvc071.htm
我喝小米粥,啃咸菜,干了一晚上。
才眯一会,刚起炕。
如果DLL导出来的C类型的函数,得到参数是不可能的,除非在主程序调用的时候挡截API,不过那也只能得到参数的个数,想到得到准确的参数类型还要进一步分析……
搞反向工程?做什么?
到底有高手没??PE+ASM
用PE将DLL翻遍数据区,再用ASM把找不完的数据区翻一遍。
我就是气不过,找不到参数类型列表。
impossible???
请各位大虾,最后冲击一次。
除了参数个数,还能不能挖出来点什么??
搞手都是自己反汇编,自己跟踪调试,自己分析,不可能有程序自动获取参数个数及参数含义的
这个标题有些夸张
转帖:
使用Microsoft Visual Studio的工具DEPENDS.EXE可以查看动态库的接口函数,但如何能够看到这个动态库接口函数的参数呢?
---------------------------------------------------------------
可以通过反汇编来知道接口函数的参数,建议使用W32DSM来分析,也可以直接使用VC来分析,就是麻烦一点。
现在使用W32DSM来具体说明:
1。先打开需要分析的DLL,然后通过菜单功能-》出口来找到需要分析的函数,双击就可以了。
它可以直接定位到该函数。
2。看准该函数的入口,一般函数是以以下代码作为入口点的。
push ebp
mov ebp, esp
...
3。然后往下找到该函数的出口,一般函数出口有以下语句。
...
ret xxxx;//其中xxxx就是函数差数的所有的字节数,为4的倍数,xxxx除以4得到的结果
就是参数的个数。
其中参数存放的地方:
ebp+08 //第一个参数
ebp+0C //第二个参数
ebp+10 //第三个参数
ebp+14 //第四个参数
ebp+18 //第五个参数
ebp+1C //第六个参数
。。。。
-------------------------------------------
还有一种经常看到的调用方式:
sub esp,xxxx //开头部分
//函数的内容
。。。
//函数的内容
add esp,xxxx
ret //结尾部分
其中xxxx/4的结果也是参数的个数。
-------------------------------------------------
还有一种调用方式:
有于该函数比较简单,没有参数的压栈过程,
里面的
esp+04就是第一个参数
esp+08就是第二个参数
。。。
esp+xx就是第xx/4个参数
你说看到的xx的最大数除以4后的结果,就是该函数所传递的参数的个数。
----------------------------------------------
到现在位置,你应该能很清楚的看到了传递的参数的个数。至于传递的是些什么内容,还需要进一步的分析。
最方便的办法就是先找到是什么软件在调用此函数,然后通过调试的技术,找到该函数被调用的地方。一般都是PUSH指令
来实现参数的传递的。这时可以看一下具体是什么东西被压入堆栈了,一般来说,如果参数是整数,一看就可以知道了,
如果是字符串的话也是比较简单的,只要到那个地址上面去看一下就可以了。
如果传递的结构的话,没有很方便的办法解决,就是读懂该汇编就可以了。对于以上的分析,本人只其到了抛砖引玉,
希望对大家有点用处。
楼上这个帖子早就看过了。按照它这种方法还是很难看到具体的参数类型。如果单纯就某个软件来言,我可以慢慢的根据汇编猜测出它的各个参数,如果想来个通用的方法,想必没有,不然软件也太好反汇编出源代码了,那我们还能够靠软件吃饭吗?
不过对于编译器厂商来说,应该留有一手未公开的东西,在DLL中放一些额外的数据,可以根据它们查看具体的参数类型。
要想真正取得参数类型,并不容易,最多可以通过PUSH的次数,看出参数的个数。
你是在分析别人的程序吧!这么难的事情,还想投机?
我以前分析过ms的打印驱动的两个dll,只要找到对应版本的调试符号文件(ms提供),可以用反汇编工具看到带有函数名的asm程序,但是要想得到参数类型,你只能得到有文档(源码也可)的输出接口函数的信息
其它的内部函数,你只能通过读asm程序,自己分析自己猜测了
老想天上掉陷饼是不可能的,你死了这条心吧!
我也想知道呀。
如果真的有这样的工具,微软也不用混了,呵呵
我要取出DLL中的所有输出函数名的列表(包括地址,最好还有参数类型列表)。
WIN32DASM
IDA PRO
有功能可以查看 DLL导出的函数
如果是普通的dll,标准的dll,那是不可能得出函数的参数类型表的,
参数的个数倒还是可以得到,类型?基本就是得不到的,除非你写出一个非常智能的代码来根据,push进来那个DWORD来分析出他的数据类型?实在太难了,普通的int数据和一个char *都是32位的DWORD,我是实在想不出,如何判断出是字符串还是int.
从另一个角度想想,如果dll里的函数名以及参数表都可以通过它自身得到,那,dll还有什么秘密可言,几乎可以认为是公开源代码了。如果dll里的函数名以及参数表都可以通过它自身得到,那编译器何必还要.lib .h 文件来辅助?
不可能得到参数列表,如果能得到还要头文件作甚!
比如有个参数是引用,是结构,或者是class的对象作为参数,或者是interface,情况太多太复杂,楼主不需要在这个不可能的事上多浪费精力了!
哎,怪只怪微软操作系统和编译器当初也没详细的设计好!
兄弟我近期在研究可不可以把Windows上的EXE和DLL,经过PE改写它的文件头之后可以在Linux上运行。
省得用VI太麻烦了,有没有高手给我一段Linux上的PE结构??
不升感谢!!
对于参数的解析很多人已经问过了,手工分析可行,不过效率却不敢恭唯
这个问题的一部分本是可以机器分析的,只不过由于编译器之间的差异使这个问题更加困难,通过某些开源的反汇编工具可以分析出参数的基本类型,即长度和基本类型,不过对于向指针类型这样的复杂类型,由于传递的参数值对不同结构的指针的传值方式都是相同的,因此具体结构的解析则要深入对该指针类型的偏移量的访问,由于在这一点上并没有明确的标准,这也是无法完全自动实现的根本原因
因此,我将这个问题归结于非标准化带来的差异
如果要实现自动反编译之类的功能,恐怕也是一个值得深究的研究型题目了,需要从很广的面上来抽象出各种应用的特征和语义表述,这在当前是没有可能的
PE格式没有定义任何所谓的参数类型表,只定义了一个重分配表和一个入口依移使得加载器能够计算出绝对地址,从而能够将调用转换为一个 call 或 jmp 调用,这也是导出表的唯一作用
richmain (吕起民)
-----------------------------------------
此人是不是“软媒”的那个SB ,有点面熟。耶
楼上的,不管是不是,只要现在遵守CSDN版规就可以了,以前的事情可以不再追究
导出函数可以看到,VC不是有个自带的工具吗?
参数列表不可能得到,除非dll这种模型有budge,
我觉得楼主是SB,我也可以这样说
:一个简单的问题,谁能在VC里给我凋
int 10h (bios中断10 )
我给1000分,
看谁他ma会
100分算个b啊。
不要想空手套白狼啦。
这种问题没有解的
没有一劳永逸的方法吧,不过如果是具体的程序,似乎也没有哪个不能被破解。
回复人: yafizyh(亚斐) ( ) 信誉:99 2005-7-10 19:10:19 得分: 0
richmain (吕起民)
-----------------------------------------
此人是不是“软媒”的那个SB ,有点面熟。耶
这两天我在网上看到软媒的招聘,说是1W至1.5W,我现在才9K,是不真的啊?是真的我来啊。
反正我们公司由3个是1.5瓦的[算我一个吧],0.9瓦的有很多。。
0.9瓦都是04毕业的,只有1个是03毕业的。
0.9瓦需求量最大。
It's actually possible, if you have the debug symbol files (PDB files). Microsoft actually makes debug symbols files available online for developer.
Anyone has used them?
With debug symbol files, your program can have the same information a debugger has.
Check source code here:
http://www.debuginfo.com/examples/src/LocalsByAddr.cpp
Read Matt Pietrek's article:
http://msdn.microsoft.com/msdnmag/issues/02/03/hood/default.aspx
只能说导出函数名可以,知道参数就不可能了。除非你去破解。。。。