研究WINNT.H里面的導(dǎo)入名表結(jié)構(gòu)體_IMAGE_IMPORT_BY_NAME 時(shí),發(fā)現(xiàn)一個(gè)問題,結(jié)構(gòu)體成員Name數(shù)組竟然是1,但是實(shí)際上反匯編看到是一個(gè)不同長度的字符串。怎么實(shí)現(xiàn)的呢?很多人在網(wǎng)上提到如下說法,但沒有深入分析為什么。這里就給出一個(gè)參考例子。說明怎么搭建那個(gè)名字表的。當(dāng)然這個(gè)名字表都是由
- typedef struct _IMAGE_THUNK_DATA32 {
- union {
- PBYTE ForwarderString;
- PDWORD Function;
- DWORD Ordinal;
- PIMAGE_IMPORT_BY_NAME AddressOfData;
- } u1;
- } IMAGE_THUNK_DATA32;
結(jié)構(gòu)指向的。IMAGE_THUNK_DATA32則由struct _IMAGE_IMPORT_DESCRIPTOR
中的OriginalFirstThunk;指向。
- typedef struct _IMAGE_IMPORT_BY_NAME {
- WORD Hint;
- BYTE Name[1];
- } IMAGE_IMPORT_BY_NAME;
【網(wǎng)上的很多說法】其中Hint字段的內(nèi)容是可選的,如果它不是0,則它也表示函數(shù)的序號,我們編程是不必考慮它。雖然上面的定義中Name數(shù)組只包含一個(gè)元素,但其實(shí)它是一個(gè)變長數(shù)組,保存的是一個(gè)以NULL結(jié)尾的字符串,也就是函數(shù)名。
該程序演示了創(chuàng)造變長數(shù)組的辦法。必須用動(dòng)態(tài)開辟內(nèi)存辦法實(shí)現(xiàn)。
必要聲明成指針,然后在malloc的時(shí)候,根據(jù)iNum數(shù)目進(jìn)行申請,譬如iNum為5個(gè)int,
這可以這樣 p = (test *)malloc(sizeof(test) + (iNum - 1) * sizeof(int));
這樣,后面的內(nèi)容可以通過p->data[i]訪問了.
- #include<iostream>
- using namespace std;
- //#pragma pack(1)如果是設(shè)置了按字節(jié)填充,則后面int len1=sizeof(impname)+ strlen(s1)即可。
- //否則需要減一。可以在各個(gè)元素之間用0隔開。
- typedef struct IMPNAME
- {
- short int hint; //模擬函數(shù)序號
- char name[1]; //模擬函數(shù)名
- } impname;
- int main()
- {
- impname *p,*s[2];
- char s1[ ]="add";
- char s2[ ]="substruct";
- char *q;
- int len1=sizeof(impname)+ strlen(s1)-1;
- int len2=sizeof(impname)+ strlen(s2)-1;
- int l=len1+len2;
- p=(impname*) malloc(l);
- p->hint=0;
- strcpy(p->name,s1);
- cout<<p->hint<<endl;
- cout<<p->name<<endl;
- s[0]=p;
- q=(char*)p; //指針類型變換,強(qiáng)制為單個(gè)字節(jié)的指針類型??梢园醋止?jié)增加步長,否則按4的倍數(shù)增加,如p+x,實(shí)際上是p+4*x;
- q=q+len1;
- p=(impname*)q; //類型轉(zhuǎn)換為原來的類型指向結(jié)構(gòu)體的。
- p->hint=1;
- strcpy(p->name,s2);
- cout<<p->hint<<endl;
- cout<<p->name<<endl;
- s[1]=p;
- cout<<"------------------------------"<<endl;
- cout<<"order="<<s[0]->hint<<endl;
- cout<<"function name="<<s[0]->name<<endl;
- cout<<"order="<<s[1]->hint<<endl;
- cout<<"function name="<<s[1]->name<<endl;
- return 0;
- }
BYTE Name[1], 這個(gè)變量定義看起來很奇怪,是嗎?代學(xué)生: 是的,我很少見到這種定義。 通常我們會(huì)定義 char buffer[256], BYTE data[8]; 等類型。 BYTE Name[1], 只包含一個(gè)元素的數(shù)組,它也裝不下后面的"MessageBoxA"字符串啊。代老師:這種定義是一種指針的變通用法。 如果你真要定義成數(shù)組來包含后面的字符串,你定義成多大呢?定義成100,短字符串浪費(fèi), 長字符串可能就真能碰到一個(gè)101個(gè)字符的名字,你定義的還是占不下。 所以說,這個(gè)Name[1], 不是要你往里面裝東西的,C 語言里,你可以借助這個(gè)Name 變量訪問到它對應(yīng)的地址。 這種用法通常是很少用的。因?yàn)樗『芏?,例如結(jié)構(gòu)后面不能再定義其它變量了,必須是最后一個(gè),定義了 數(shù)組又不用它裝東西,也不符合數(shù)組的初衷. 所以你只有明白這個(gè)道理就可以了。 代學(xué)生:既然它那么不好用,為什么還那樣定義呢。代老師:還是那句話,是變通。 你看,它簡潔,它完成了使命。否則你就要把結(jié)構(gòu)變一變,例如按常規(guī)估計(jì)應(yīng)該是這樣子。 WORD Hint; BYTE *pName; 然后你要求微軟說,Hint 后面不要跟字符串,要跟一個(gè)地址。這樣C語言好寫。 好比說大部分人沿著盤山路往山上走,也有人愿意盤著荊棘往山上爬,后者繞了近路,但風(fēng)險(xiǎn)也大。 代學(xué)生:講了這么多,其實(shí)我看一個(gè)word 后面跟著一個(gè)0字終結(jié)符字符串,還是很好理解的嗎。代老師:C 語言以其簡潔,高效,使我們受益良多。但在某些特殊的情況下,它也會(huì)力不從心。有時(shí)刻當(dāng)你看著一堆堆 結(jié)構(gòu)套結(jié)構(gòu),一堆堆宏套宏令你頭暈時(shí),而看看它最終的list 表或二進(jìn)制輸出反而能令你豁然開朗。 哦,有點(diǎn)扯遠(yuǎn)了。 我還是最喜歡C的。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點(diǎn)擊舉報(bào)。