标 题:
【原创】让EXE导出函数
作 者:
ylp1332
时 间: 2007-12-20,21:33 链 接: http://bbs.pediy.com/showthread.php?t=56840
初步搞定。
问题来源: 偶然发现OllyDBG.exe导出了一堆函数,这些函数都是供其插件调用的。对这种体系结构很感 兴趣,想弄清楚它的实现原理。后来又看到梁肇新的书《编程高手箴言》第278页提到的调用 门,觉得都应该差不多。
三种不同的解决办法(原理可能是一样的,:)):
1)在导出函数声明之前加上__declspec(dllexport)。例: __declspec(dllexport) int Add(int a, int b); __declspec(dllexport) int Sub(int a, int b); __declspec(dllexport) int Mul(int a, int b); __declspec(dllexport) int Div(int a, int b);
2)在链接器参数中设置。例: #pragma comment(linker, "/EXPORT:_Add,@1,NONAME") #pragma comment(linker, "/EXPORT:_Sub,@2,NONAME") #pragma comment(linker, "/EXPORT:_Mul,@3,NONAME") #pragma comment(linker, "/EXPORT:_Div,@4,NONAME")
3)添加一个def文件,例: EXPORTS Add @1 NONAME Sub @2 NONAME Mul @3 NONAME Div @4 NONAME 另需要在链接器命令行参数中指定def文件名: /DEF:Callee.def 注意:在def文件中不要有 LIBRARY [library][BASE=address] 这样的语句。
相比较而言,后两种方法可以设置更多的参数。
函数举例:
extern "C" {
int Add(int a, int b) { return (a + b); }
int Sub(int a, int b) { return (a - b); }
int Mul(int a, int b) { return (a * b); }
int Div(int a, int b) { if (b == 0) return 0; else return (a / b); }
}
编译时会自动生成相应的导出库(lib)文件,供调用者使用。
调用方法和普通的动态链接库调用一样。 调用者必须能够找到被调用者的位置,否则报错,被调用者是否运行不影响。
调用代码举例:
extern "C" { int Add(int a, int b); int Sub(int a, int b); int Mul(int a, int b); int Div(int a, int b); }
#pragma comment (lib, "Callee.lib")
void CCallerDlg::OnBnClickedCalculate() { // TODO: Add your control notification handler code here UpdateData(TRUE);
switch (((CComboBox *)GetDlgItem(IDC_COMBO_OPERATOR))->GetCurSel()) { case ADD: { m_iResult = Add(m_iNum1, m_iNum2); break; } case SUB: { m_iResult = Sub(m_iNum1, m_iNum2); break; } ... ...
我在OD中跟了一下,发现这跟调用动态链接库也差不多。 不过那几个函数被映射到下面的地址处:
003810F0 > 8B4424 08 mov eax, dword ptr [esp+8] 003810F4 8B4C24 04 mov ecx, dword ptr [esp+4] 003810F8 03C1 add eax, ecx 003810FA C3 retn 003810FB CC int3 003810FC CC int3 003810FD CC int3 003810FE CC int3 003810FF CC int3 00381100 > 8B4424 04 mov eax, dword ptr [esp+4] 00381104 2B4424 08 sub eax, dword ptr [esp+8] 00381108 C3 retn 00381109 CC int3 0038110A CC int3 0038110B CC int3 0038110C CC int3 0038110D CC int3 0038110E CC int3 0038110F CC int3 00381110 > 8B4424 04 mov eax, dword ptr [esp+4] 00381114 0FAF4424 08 imul eax, dword ptr [esp+8] 00381119 C3 retn 0038111A CC int3 0038111B CC int3 0038111C CC int3 0038111D CC int3 0038111E CC int3 0038111F CC int3 00381120 > 8B4C24 08 mov ecx, dword ptr [esp+8] 00381124 85C9 test ecx, ecx 00381126 75 03 jnz short 0038112B 00381128 33C0 xor eax, eax 0038112A C3 retn
跟常规的动态链接库被映射到高地址处略有不同。 还不知道是什么原因。
结论: EXE完全可以和DLL一样导出函数,一样被调用。
进一步的工作: 我发现这个例子跟OllyDbg.exe还是有些不同,跟“调用门”的说法也有不同。这里实际上还是 跟DLL差不多的原理。下一步争取实现一个跟OllyDbg.exe差不多的例子。
致谢: 感谢海风月影、北极星2003、默数悲伤所提供的思路。
|