首页
论坛
专栏
课程

[原创]让EXE导出函数

2007-12-20 21:33 23387

[原创]让EXE导出函数

2007-12-20 21:33
23387
初步搞定。

问题来源:
偶然发现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、默数悲伤所提供的思路。

源代码和例子见附件。

[招聘]欢迎市场人员加入看雪学院团队!

上传的附件:
最新回复 (19)
sudami 25 2007-12-20 22:41
2
0
学习~~~
benbentaiyang 1 2007-12-20 23:38
3
0
你说的是用插件来调用,插件在使用过程中被加载,而exe本身也已经加载,所以能调用。但是如果其他exe文件要调用这个exe文件的函数,是不是也要像加载dll一样先加载这个exe呢?和dll加载方法一样吗? 我想如果这个exe文件运行起来之后,别的exe调用它是不是就没问题了? 还没有亲自试验,只是弱弱地问一下!
海风月影 17 2007-12-20 23:43
4
0
[QUOTE=ylp1332;394025]初步搞定。

注意:在def文件中不要有
LIBRARY [library][BASE=address]
这样的语句。
[/QUOTE]

学习,原来是这个原因
firefly 4 2007-12-21 09:25
5
0
学习了,有机会试试。
yijun8354 12 2007-12-21 12:47
6
0
收藏了~~~
rick 7 2007-12-21 13:30
7
0
exe导出函数和dll导出函数基本上完全一样的.
其函数的调用方式也完全一样,可以隐式连接,或者显示连接.

如果一个Exe调用另一个Exe的导出函数, 这和exe调用dll的导出函数完全一样.
被调用的Exe文件也会作为 一个模块 加载到当前Exe的进程空间.
海风月影 17 2007-12-21 13:43
8
0
对了,忘记补充给楼主了

按照楼主的意思,还必须加上重定位表才行

#pragma comment(linker,"/FIXED:NO")
combojiang 26 2007-12-21 13:48
9
0
哈,其实windows内核就是一个有导出函数的exe。对于楼主的共享精神,赞一个
ylp1332 15 2007-12-21 22:51
10
0
呵呵,你运行一下附件里面的例子就知道了,完全跟dll一样的原理。
ylp1332 15 2007-12-21 22:54
11
0
我觉得OllyDBG.exe的调用方式可能还是有些不一样,不知道你有没有研究?
ylp1332 15 2007-12-21 22:56
12
0
谢谢!我再继续尝试,呵呵
liuzewei 3 2007-12-22 11:30
13
0
学习,跟高手开阔眼界!有新意的原创帖,支持!
wangdell 6 2007-12-27 17:39
14
0
wyl?
学习。
elance 6 2007-12-27 21:55
15
0
好文章,学习一下。
zklhp 2008-2-5 19:55
16
0
是ntoskrnl.exe?
zhouweizhu 2008-3-20 11:50
17
0
好文章,学习一下
foolpanda 2008-4-5 19:54
18
0
VC中有一种支持自动化的Exe,简单的可以用Dialog支持自动化实现,在VC6中可以用ClassWizard实现。  有兴趣可以看看。
这种EXE也是有导出函数的,可以供其它EXE调用。
VC6有一些这种例子。
bwin 2008-4-8 13:11
19
0
留名。。
以后好搜索。。
yber 2017-8-3 15:53
20
0
赞,感谢分享
游客
登录 | 注册 方可回帖
返回