青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-90  評(píng)論-947  文章-0  trackbacks-0

突然想到個(gè)問題,EXE可否像DLL一樣導(dǎo)出函數(shù)呢?于是就起來做試驗(yàn)——

 

靜態(tài)鏈接調(diào)用

嗯,先建立一個(gè)EXE,內(nèi)容很簡單:

 

#include "stdafx.h"

#define EXE_LIBRARY

#include "ExeLibrary.h"

 

EXE_LIBRARY_API int Sum(int a, int b)

{

    return a + b;

}

 

int APIENTRY _tWinMain(_In_ HINSTANCE     hInstance,

                       _In_opt_ HINSTANCE hPrevInstance,

                       _In_ LPTSTR        lpCmdLine,

                       _In_ int           nCmdShow)

{

    return 0;

}

 

Sum函數(shù)是等下用來測試的。其中ExeLibrary.h 中模仿系統(tǒng)生成的DLL頭文件進(jìn)行了宏定義:

 

#ifdef EXE_LIBRARY

#define EXE_LIBRARY_API __declspec(dllexport)

#else

#define EXE_LIBRARY_API __declspec(dllimport)

#endif

 

EXE_LIBRARY_API int Sum(int a, int b);

 

 

然后建立另一個(gè)EXE

 

#include "../ExeLibrary/ExeLibrary.h"

#pragma comment(lib, "ExeLibrary.lib")

 

int main()

{

    int s = Sum(1, 2);

 

    return s;

}

 

然后運(yùn)行:

clip_image001

 

能跑,運(yùn)行結(jié)果也正確,說明函數(shù)被正確執(zhí)行。

 

查了下進(jìn)程列表,木有ExeLibrary.exe

再查調(diào)試環(huán)境的模塊列表:

clip_image002

ExeLibrary赫然在目。

 

整個(gè)運(yùn)行過程中,WinMain 函數(shù)木有進(jìn)入。嘗試

 

動(dòng)態(tài)加載調(diào)用

先為剛才的ExeLibrary添加一個(gè)def文件:

 

LIBRARY

 

EXPORTS

    Sum

 

然后新建另一個(gè)EXE

 

#include <Windows.h>

#include <tchar.h>

 

int main()

{

    HMODULE hModule = LoadLibrary(_T("ExeLibrary.exe"));

 

    if (hModule == nullptr)

    {

        return 0;

    }

 

    typedef int (*FnSum)(int a, int b);

    FnSum Sum = (FnSum)GetProcAddress(hModule, "Sum");

 

    int s = 0;

 

    if (Sum != nullptr)

    {

        s = Sum(1, 2);

    }

 

    FreeLibrary(hModule);

 

    return s;

}

 

運(yùn)行結(jié)果:

 

clip_image003

 

同剛才一樣,一切正常。

 

結(jié)論

可以像DLL一樣,在EXE里導(dǎo)出函數(shù)。調(diào)用時(shí)可以靜態(tài)鏈接也可以動(dòng)態(tài)加載。EXE只作為一個(gè)進(jìn)程內(nèi)的模塊被加載,不會(huì)新起一個(gè)進(jìn)程。加載過程中EXE中的WinMain函數(shù)不會(huì)被調(diào)用。

 

例程下載:http://pan.baidu.com/s/1mgqTYBI

posted on 2012-12-01 11:41 溪流 閱讀(8162) 評(píng)論(15)  編輯 收藏 引用 所屬分類: Windows

評(píng)論:
# re: EXE導(dǎo)出函數(shù) 2012-12-01 13:15 | OwnWaterloo
exe和dll還是有很多區(qū)別的。
首先entrypoint肯定就被忽略了。
其次重定位和依賴加載好像也會(huì)有問題。

比如試試這個(gè)?
int error_code;
__declspec(dllexport) int get_error(void) { return error_code; }
__declspec(dllimport) void set_error(int x) { error_code = x; }

get和set產(chǎn)生的指令里會(huì)有error_code的地址。
如果是dll,加載時(shí)指令中的地址會(huì)被正確地重定位。
而exe不行,即使保留重定位信息也不行。

exe可以被加載應(yīng)該是為了里面的資源而不是代碼。
  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-02 12:09 | 溪流
@OwnWaterloo
不懂,為啥例子中一個(gè)是export一個(gè)是import?  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-02 16:36 | OwnWaterloo
@溪流
手誤。。。我的錯(cuò)。。。  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-02 16:48 | OwnWaterloo
@溪流
兩個(gè)都是dllexport。兩個(gè)函數(shù)產(chǎn)生的代碼都會(huì)用上error_code的地址。

鏈接產(chǎn)生這個(gè)dll/exe的時(shí)候,是很難確切地知道加載后該dll/exe的地址。同樣也很難確切知道error_code的地址,因?yàn)樗蚫ll/exe被加載后的基地址之間的偏移是鏈接后就固定了的。

于是鏈接器只能先假設(shè)dll/exe會(huì)被加載到某個(gè)位置(首選基地址),然后根據(jù)它產(chǎn)生代碼。

比如一種極端情況,將dll/exe復(fù)制一份本地文件(首選基地址相同),然后loadlibrary它倆。
那么,至少有一個(gè)dll/exe是無法被加載到首選基地址的,也就是set/get的指令中使用的地址是不正確的。

如果是dll,沒有被加載到首選基地址的話,就會(huì)發(fā)生重定項(xiàng)。set/get的指令會(huì)相應(yīng)的修改。
而exe,我記得loader就不會(huì)做這個(gè)工作,于是就。。。
  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-02 16:50 | OwnWaterloo
@溪流
另外,load是不會(huì)根據(jù)dll/exe后綴名來判斷是否是dll還是exe。
它是根據(jù)pe格式中的一個(gè)域來判斷的。具體位置我忘了。。。不過dumpbin好像能顯示出來。

也就是說。。。很多那些后綴是exe(甚至是ocx什么的),而且加載后也能成功調(diào)用里面函數(shù)的文件,其實(shí)按pe格式來說都是dll文件,只是后綴名沒有用dll而已。
  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-02 16:58 | 溪流
@OwnWaterloo
懂了~就是說EXE當(dāng)DLL用,不會(huì)被重定向咯?改天試下哈  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-02 23:47 | 朱峰e(cuò)verettjf
當(dāng)時(shí)我也做了個(gè)類似的研究,
http://m.shnenglu.com/everett/archive/2012/05/25/176073.aspx
交流交流  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-04 10:58 | zuhd
@OwnWaterloo
我做了個(gè)實(shí)驗(yàn),exe的導(dǎo)出函數(shù)中調(diào)用全局變量也是沒問題的,沒出現(xiàn)樓上所說的崩潰現(xiàn)象,如果按照pe格式來理解的話,即使是exe應(yīng)該也會(huì)被重定向吧?  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-04 11:00 | zuhd
樓主的例子我沒下載成功,用的是朱峰e(cuò)verettjf提供看雪里的例子,我新增加了兩個(gè)函數(shù),調(diào)用全局變量。如果需要提供現(xiàn)場的話,留個(gè)郵箱。  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-04 15:12 | OwnWaterloo
@zuhd
沒有崩潰=沒有問題=程序正確?

*(int*)隨便寫個(gè)什么地址 = 12; // 只要運(yùn)氣好,同樣不會(huì)立即崩潰。  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-04 16:13 | OwnWaterloo
本來應(yīng)該用高級(jí)評(píng)論將重點(diǎn)高亮的,但不知道cppblog出了什么問題用不了。只能眼睛尖點(diǎn)了。。。

1. test files

module.c 導(dǎo)出1個(gè)變量與3個(gè)函數(shù)

__declspec(dllexport) int error_code;
__declspec(dllexport) int get(void) { return error_code; }
__declspec(dllexport) void set(int x) { error_code = x; }
int main(void) { return 0; }

main.c 輸出變量地址、函數(shù)地址以及函數(shù)包含的指令

#include <stdio.h>

__declspec(dllimport) int error_code;
__declspec(dllimport) int get(void);
__declspec(dllimport) void set(int x);

int main(void)
{
int i;
unsigned char const* p;

printf("%p\n", (void*)&error_code);

p = (unsigned char*)get;
printf("%p:", p);
for (i=0; i<12; ++i) printf(" %02X", p[i]);
printf("\n");

p = (unsigned char*)set;
printf("%p:", p);
for (i=0; i<12; ++i) printf(" %02X", p[i]);
printf("\n");

return 0;
}


2. dll

編譯
cl /LD /O1 module.c /link /noentry

查看首選基地址
dumpbin /all module.dll | find /i "image base"
10000000 image base (10000000 to 10004FFF)

查看反匯編與重定項(xiàng)
dumpbin /disasm /relocations module.dll

File Type: DLL

10001000: A1 00 30 00 10 mov eax,dword ptr ds:[10003000h]
10001005: C3 ret
10001006: 8B 44 24 04 mov eax,dword ptr [esp+4]
1000100A: A3 00 30 00 10 mov dword ptr ds:[10003000h],eax
1000100F: C3 ret

BASE RELOCATIONS #4
1000 RVA, C SizeOfBlock
1 HIGHLOW 10003000
B HIGHLOW 10003000

10001000 處(get的第1條)指令的操作數(shù)(地址在10001001)是 10003000
1000100A 處(set的第2條)指令的操作數(shù)(地址在1000100B)也是 10003000
注意"File Type: DLL",這是根據(jù)PE的域來的。

編譯并運(yùn)行得到的輸出是
cl main.c module.lib && main.exe
10003000
10001000: A1 00 30 00 10 C3 8B 44 24 04 A3 00
10001006: 8B 44 24 04 A3 00 30 00 10 C3 00 00

error_code的地址和指令中使用的地址是相同的。


3. dll relocation

上面 module.dll 恰好加載在首選基地址,所以沒有發(fā)生重定項(xiàng)。
要演示重定項(xiàng)發(fā)生的情況, 可以將 module.dll 復(fù)制一份, 然后用 LoadLibrary 加載。
或者直接首選基地址為一個(gè)會(huì)沖突的, exe的默認(rèn)基地址0x400000。

cl /LD /O1 module.c /link /noentry /base:0x400000

dumpbin /all module.dll | find /i "image base"
400000 image base (00400000 to 00404FFF)

dumpbin /disasm /relocations module.dll
00401000: A1 00 30 40 00 mov eax,dword ptr ds:[00403000h]
00401005: C3 ret
00401006: 8B 44 24 04 mov eax,dword ptr [esp+4]
0040100A: A3 00 30 40 00 mov dword ptr ds:[00403000h],eax
0040100F: C3 ret

BASE RELOCATIONS #4
1000 RVA, C SizeOfBlock
1 HIGHLOW 00403000
B HIGHLOW 00403000

cl main.c module.lib && main.exe
00393000
00391000: A1 00 30 39 00 C3 8B 44 24 04 A3 00
00391006: 8B 44 24 04 A3 00 30 39 00 C3 00 00

對(duì)比 dumpbin 得到的反匯編與 main.exe 的輸出,可以發(fā)現(xiàn)指令中的操作數(shù)有相應(yīng)的修改,以正確的使用00393000上的變量error_code。


4. dll fixed

如果鏈接時(shí)選擇基地址固定
cl /LD /O1 module.c /link /noentry /base:0x400000 /fixed

產(chǎn)生的dll里就沒有重定項(xiàng)信息
dumpbin /relocations module.dll

并且選擇的是一個(gè)肯定會(huì)沖突的基地址,所以加載main.exe就會(huì)失敗。

main.exe


5. exe export

默認(rèn)exe是不會(huì)包含重定項(xiàng)信息的
cl /O1 module.c && dumpbin /relocations module.exe

File Type: EXECUTABLE IMAGE

注意"File Type: EXECUTABLE IMAGE",這是根據(jù)PE的域來的。

并且首選基地址也是沖突的。
dumpbin /all module.exe | find /i "image base"
400000 image base (00400000 to 0040BFFF)

但是讓 main.c 鏈接到 module.exe 可以運(yùn)行成功(之前dll fixed的情況是加載 main.exe 失敗)
cl main.c module.lib & main.exe
0039B700
00391000: A1 00 B7 40 00 C3 8B 44 24 04 A3 00
00391006: 8B 44 24 04 A3 00 B7 40 00 C3 33 C0

注意指令里的操作碼,并沒有修改為error_code的地址:0039B700。
如果真的調(diào)用了get和set,也只是讀寫了其他的地址,而不是error_code。
bug已經(jīng)產(chǎn)生了。 沒崩只是運(yùn)氣, 那個(gè)地址恰好有讀寫權(quán)限。
而且實(shí)驗(yàn)代碼一般都比較短,跑完馬上就退出了,這種意外的寫入產(chǎn)生的影響也不一定能發(fā)現(xiàn)。

6. exe export with relocation information

可以用 /fixed:no 附帶上重定項(xiàng)信息
cl /O1 module.c /link /fixed:no

dumpbin /relocations module.exe 會(huì)產(chǎn)生很多輸出,因?yàn)樗€引用了libc。

而讓 main.c 鏈接到 module.exe 并運(yùn)行的同樣不會(huì)發(fā)生重定項(xiàng)
cl main.c module.lib & main.exe
0039B700
00391000: A1 00 B7 40 00 C3 8B 44 24 04 A3 00
00391006: 8B 44 24 04 A3 00 B7 40 00 C3 33 C0
  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-05 00:11 | 溪流
@OwnWaterloo
呀,信息量好大,學(xué)習(xí)了~!本想到周末研究一番的~  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-05 09:44 | zuhd
@OwnWaterloo
可以這樣理解嗎?
1,用lib的方式加載exe的導(dǎo)出函數(shù),
#pragma comment(linker,"/FIXED:NO") ,
這樣exe就和dll一樣,均不會(huì)有問題。
2,用loadlibrary的方式加載exe的到處函數(shù),
即使是重定向,在操作全局變量,也不會(huì)定向到全局變量的正確地址。
如:
而讓 main.c 鏈接到 module.exe 并運(yùn)行的同樣不會(huì)發(fā)生重定項(xiàng)
cl main.c module.lib & main.exe
0039B700
00391000: A1 00 B7 40 00 C3 8B 44 24 04 A3 00
00391006: 8B 44 24 04 A3 00 B7 40 00 C3 33 C0  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-05 14:28 | OwnWaterloo
@zuhd
我記得是只與文件類型(PE中的那個(gè)域)有關(guān),與加載方式(隱式加載/顯式加載)無關(guān)。

只要文件類型是exe,加載器就不會(huì)去處理重定項(xiàng)。
如果exe沒有加載到首選基地址,里面的指令操作的就不是預(yù)想中的地址。

前面說loadlibrary的意思是:這是一種讓dll/exe無法加載到首選基地址的方法。
如果將dll/exe文件復(fù)制一份(文件各種信息都是相同的),然后用loadlibrary加載這兩者,那兩者之一肯定之多有一個(gè)是被加載到首選基地址。于是就可以觀察另一個(gè)的情況了。

但前面為了偷懶。。。 就沒有用這個(gè)方法,而是用/base:0x400000 —— 這個(gè)是exe文件默認(rèn)的基地址 —— 讓dll無法加載到首選基地址。
  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-06 09:24 | zuhd
多謝OwnWaterloo
如果可以的話 希望能在cppblog單開一主題,探其究竟。  回復(fù)  更多評(píng)論
  
# re: EXE導(dǎo)出函數(shù) 2012-12-06 22:41 | OwnWaterloo
@zuhd
cppblog的排版功能太弱了。。。 寫東西很費(fèi)勁。。。  回復(fù)  更多評(píng)論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美一级大片在线观看| 欧美网站在线| 亚洲午夜一区二区| 99热这里只有成人精品国产| 欧美国产一区在线| 欧美大片在线观看一区| 亚洲国产视频一区二区| 性久久久久久久| 亚洲乱码国产乱码精品精天堂| 国内久久精品| 精品999在线播放| 亚洲精品欧美一区二区三区| 夜夜爽99久久国产综合精品女不卡| 国产日韩专区在线| 亚洲在线一区| 午夜欧美大片免费观看| 欧美在线观看一二区| 蜜桃久久精品乱码一区二区| 亚洲国产精品va在线看黑人 | 欧美连裤袜在线视频| 红杏aⅴ成人免费视频| 久久漫画官网| 久久婷婷影院| 亚洲日本一区二区| 欧美黄色aaaa| 欧美激情第五页| 亚洲一级片在线看| 亚洲欧美日韩直播| 激情欧美一区二区三区| 欧美成人一区二区三区| 欧美精品三级| 新狼窝色av性久久久久久| 久久精品人人爽| 亚洲激情视频| av成人免费在线观看| 国产精品外国| 欧美va天堂在线| 欧美日韩调教| 久久久亚洲影院你懂的| 欧美成人综合在线| 亚洲欧美综合国产精品一区| 欧美一区二区三区视频在线观看| 亚洲国产精品久久久| 日韩一级精品| 韩国女主播一区二区三区| 亚洲欧洲一区二区三区在线观看 | 99re视频这里只有精品| 一本色道88久久加勒比精品| 国产欧美一级| 亚洲黄色免费电影| 国产欧美日韩一区二区三区在线 | 亚洲综合色婷婷| 欧美一区二区免费观在线| 亚洲国产精品久久91精品| 亚洲一级黄色片| 亚洲黄一区二区三区| 亚洲在线成人精品| 亚洲伦伦在线| 久久天堂av综合合色| 一本在线高清不卡dvd| 欧美一区二区性| 亚洲私拍自拍| 久久人人爽人人| 欧美一区二区三区播放老司机| 麻豆国产精品777777在线| 欧美一区二区三区四区在线| 欧美激情精品久久久久久免费印度 | 亚洲国产精品久久久久婷婷884 | 亚洲网站在线看| 亚洲人被黑人高潮完整版| 午夜天堂精品久久久久| 一本一本久久| 牛牛精品成人免费视频| 欧美一区免费| 欧美日韩亚洲系列| 亚洲高清视频在线| 国产综合久久久久影院| 亚洲一区免费看| 中文av一区特黄| 欧美电影免费观看高清完整版| 久久精品官网| 国产精品久久久久高潮| 亚洲精品韩国| 亚洲日本免费| 老司机一区二区| 久久久之久亚州精品露出| 国产精品日韩在线观看| 欧美大片在线观看一区二区| 国产精品一区二区你懂的| 一区二区不卡在线视频 午夜欧美不卡在| 在线欧美视频| 久久精品99国产精品日本| 性欧美超级视频| 国产精品分类| 亚洲视频一二| 亚洲欧美卡通另类91av| 欧美日韩国产首页| 亚洲精品视频免费观看| 一区二区久久久久| 欧美日韩高清在线播放| 亚洲品质自拍| 在线亚洲一区| 国产精品成人一区二区三区吃奶| 亚洲精品一区中文| 亚洲午夜电影在线观看| 欧美四级在线| 亚洲亚洲精品三区日韩精品在线视频 | 国产一区二区三区久久精品| 亚洲欧美日韩国产中文在线| 午夜精品理论片| 国产精品资源在线观看| 香蕉国产精品偷在线观看不卡| 久久激情视频免费观看| 国产一区二区三区黄| 欧美在线一级va免费观看| 久久精品夜色噜噜亚洲aⅴ| 国产专区精品视频| 另类图片综合电影| 91久久精品一区二区三区| 亚洲伦理一区| 国产精品日韩欧美大师| 西西裸体人体做爰大胆久久久| 久久久久天天天天| 亚洲黄色小视频| 欧美日韩你懂的| 午夜精品在线| 欧美国产亚洲视频| 亚洲视频在线看| 亚洲性xxxx| 欧美日韩免费在线| 欧美成人免费在线观看| 最新亚洲一区| 午夜精品婷婷| 亚洲午夜精品在线| 久久久精品视频成人| 在线精品国精品国产尤物884a| 欧美激情精品久久久| 久久久久免费| 亚洲视频一二三| 狠狠色丁香婷综合久久| 欧美麻豆久久久久久中文| 午夜激情亚洲| 亚洲国产天堂久久综合网| 午夜久久久久久久久久一区二区| 一区二区三区在线观看国产| 欧美日韩中文| 久久久久久久综合日本| 日韩视频精品| 欧美~级网站不卡| 午夜精品久久久| 亚洲激情视频网站| 国产亚洲欧美日韩美女| 欧美日韩国产综合视频在线观看中文 | 国产视频亚洲精品| 久久只精品国产| 亚洲影音先锋| 亚洲精品久久久一区二区三区| 久久成人人人人精品欧| 99在线精品观看| 18成人免费观看视频| 国产美女搞久久| 欧美在线中文字幕| 亚洲与欧洲av电影| 日韩网站免费观看| 欧美福利在线| 另类酷文…触手系列精品集v1小说| 亚洲性视频h| 日韩小视频在线观看| 亚洲丶国产丶欧美一区二区三区 | 老司机午夜精品| 久久成人免费| 欧美一区二区三区在线看 | 免费在线成人av| 久久久精品性| 久久国产精品一区二区| 亚洲欧美另类久久久精品2019| 日韩一区二区免费看| 亚洲电影免费观看高清完整版在线观看 | av不卡在线看| 国产日韩一区二区三区在线播放| 欧美欧美全黄| 欧美激情bt| 欧美日韩国产美| 99xxxx成人网| 亚洲视频久久| 亚洲影院色无极综合| 亚洲免费视频网站| 亚洲免费视频观看| 欧美一级片在线播放| 性做久久久久久免费观看欧美 | 欧美亚洲自偷自偷| 欧美一区二区三区四区在线 | 亚洲高清视频一区| 亚洲国产精品第一区二区三区 | 欧美日韩国产亚洲一区| 欧美日韩伊人| 国产精品免费视频xxxx| 国产一区二区精品| 依依成人综合视频| 亚洲人成久久|