让EXE导出函数
标 题
:
【原创】让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
、默数悲伤所提供的思路。
源代码和例子见附件。
http
:
//bbs.pediy.com/attachment.php?attachmentid=10475&d=1198157615