首页
社区
课程
招聘
[原创]让EXE导出函数
发表于: 2007-12-20 21:33 28308

[原创]让EXE导出函数

2007-12-20 21:33
28308

初步搞定。

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

源代码和例子见附件。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (19)
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
2
学习~~~
2007-12-20 22:41
0
雪    币: 234
活跃值: (61)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
你说的是用插件来调用,插件在使用过程中被加载,而exe本身也已经加载,所以能调用。但是如果其他exe文件要调用这个exe文件的函数,是不是也要像加载dll一样先加载这个exe呢?和dll加载方法一样吗? 我想如果这个exe文件运行起来之后,别的exe调用它是不是就没问题了? 还没有亲自试验,只是弱弱地问一下!
2007-12-20 23:38
0
雪    币: 7325
活跃值: (3803)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
4
[QUOTE=ylp1332;394025]初步搞定。

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

学习,原来是这个原因
2007-12-20 23:43
0
雪    币: 260
活跃值: (102)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
学习了,有机会试试。
2007-12-21 09:25
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
6
收藏了~~~
2007-12-21 12:47
0
雪    币: 288
活跃值: (112)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
7
exe导出函数和dll导出函数基本上完全一样的.
其函数的调用方式也完全一样,可以隐式连接,或者显示连接.

如果一个Exe调用另一个Exe的导出函数, 这和exe调用dll的导出函数完全一样.
被调用的Exe文件也会作为 一个模块 加载到当前Exe的进程空间.
2007-12-21 13:30
0
雪    币: 7325
活跃值: (3803)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
8
对了,忘记补充给楼主了

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

#pragma comment(linker,"/FIXED:NO")
2007-12-21 13:43
0
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
9
哈,其实windows内核就是一个有导出函数的exe。对于楼主的共享精神,赞一个
2007-12-21 13:48
0
雪    币: 281
活跃值: (3050)
能力值: ( LV12,RANK:610 )
在线值:
发帖
回帖
粉丝
10
呵呵,你运行一下附件里面的例子就知道了,完全跟dll一样的原理。
2007-12-21 22:51
0
雪    币: 281
活跃值: (3050)
能力值: ( LV12,RANK:610 )
在线值:
发帖
回帖
粉丝
11
我觉得OllyDBG.exe的调用方式可能还是有些不一样,不知道你有没有研究?
2007-12-21 22:54
0
雪    币: 281
活跃值: (3050)
能力值: ( LV12,RANK:610 )
在线值:
发帖
回帖
粉丝
12
谢谢!我再继续尝试,呵呵
2007-12-21 22:56
0
雪    币: 324
活跃值: (91)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
13
学习,跟高手开阔眼界!有新意的原创帖,支持!
2007-12-22 11:30
0
雪    币: 87
活跃值: (47)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
14
wyl?
学习。
2007-12-27 17:39
0
雪    币: 716
活跃值: (162)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
15
好文章,学习一下。
2007-12-27 21:55
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
是ntoskrnl.exe?
2008-2-5 19:55
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
好文章,学习一下
2008-3-20 11:50
0
雪    币: 217
活跃值: (30)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
VC中有一种支持自动化的Exe,简单的可以用Dialog支持自动化实现,在VC6中可以用ClassWizard实现。  有兴趣可以看看。
这种EXE也是有导出函数的,可以供其它EXE调用。
VC6有一些这种例子。
2008-4-5 19:54
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
留名。。
以后好搜索。。
2008-4-8 13:11
0
雪    币: 9
活跃值: (205)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
20
赞,感谢分享
2017-8-3 15:53
0
游客
登录 | 注册 方可回帖
返回
//