讓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