1.å¦ä½å®ä½å¯¼è´Crashç代ç ä½ç½®
2.å±å¹åè¯
å¦ä½å®ä½å¯¼è´Crashç代ç ä½ç½®
1. å¨å¼åç¯å¢ä¸å®ä½Crashé误
ãã1.1 æ®éçcrash
ããããå æ¥ççææ®éçcrash
ããããåè§å¾1(c.png)
ããããå½ä½ å¨debug模å¼ä¸è¿è¡ä¸é¢çç¨åºå°±ä¼å¼¹åºä¸é¢çæ¡ãvcå°±å¸®ä½ å®ä½å°äºé误çä½ç½®ãæ¯ä¸ªå¯¹é¶æéçæä½ãé常ç®åï¼ä¸æ¯åã
ãã1.2 è¾é¾å®ä½çcrash
ããããè¾é¾å®ä½çcrashå¾å¾æ¯ç±äºå åé误(åè§5.1 为ä»ä¹ç¨åºcrashæ¶è°ç¨å æ æ¯ä¹±ç)ãä¾å¦ä»¥ä¸ä»£ç ï¼
代ç
ããããchar *p = new char[];
ããããp[] = 0xfd;
ããããdelete[] p;
ããããprintf(p);
ãããã以ä¸ä»£ç æ两å¤é误ï¼ä¸æ¯ç¬¬2è¡çå ååè¶çï¼äºæ¯ç¬¬4è¡ä½¿ç¨è¢«å é¤çæéã
ããããä½ä»¥ä¸ä»£ç å¨vcçreleaseådebugä¸é½ä¸ä¼æ¥éãè¿ä½¿å¾è¿ç±»é误å¾é¾å®ä½ã
ããããæ£æµè¿ä¸ç±»é®é¢å¯ä»¥ä½¿ç¨BoundsCheckerå·¥å ·çFinalCheck模å¼ï¼BoundsCheckerï¼
ããããç¨BoundsCheckeræ£æµåå¯å¾å°ä¸¤ä¸ªé误ï¼Write overrun(åè¶ç) å Dangling pointer(使ç¨è¢«å é¤çæé)èä¸é½ç²¾ç¡®å®ä½å°äºåºéçä½ç½®ãæ¯ä¸ªä¸éçå·¥å ·ã
ããããåè§å¾2(c.png)
ããããåè§å¾3(c.png)
ãã1.3 注ævcçè¾åºæ¥å¿
ããããç±äºä¸äºç®åæªç¥çåå ï¼æå¯è½æ¯ç¨åºçé误太严éææ¯BoundsCheckeræ¬èº«çbugï¼ï¼BoundsChekcerææ¶ä¸è½æ£å¸¸å·¥ä½ã
ããããè¿évcçè¾åºæ¥å¿ææ¶è½æä¾ä¸äºæç¨çä¿¡æ¯ã
ããããå¨é¾æ¾çcrashä¸ï¼æå¾å¤§ä¸é¨åæ¯å¼ç¨äºéæ³çæéã
ããããææ¶å¨vcçè¾åºæ¥å¿éå¯ä»¥çå°ç±»ä¼¼äºè¿æ ·çä¿¡æ¯
ããããâemule.exe ä¸ç 0xb7 å¤æå¯è½çå¼å¸¸: 0xC: 读åä½ç½® 0xfeeeff æ¶åç访é®å²çª ãâ
ããããå¨ç¼ºå°BoundsCheckerçæ¯ææ¶ï¼è¿æ¯ä¸æ¡å¾éè¦çä¿¡æ¯ãæææ¯è¯´å¨âç¨åºå°å0xb7å¤â对âå¼ä¸º0xfeeeffçæéâè¿è¡æä½ã
ããããï¼æä¹éè¿âç¨åºå°å0xb7âæ¾å°å¯¹åºç代ç è¡å¯åç § 3.1ï¼ï¼
ããããè¿æ¡ä¿¡æ¯çéè¦æ§å¨äºï¼è¿ä¸ªæä½åªä¼è§¦åä¸ä¸ªè¦åï¼èä¸ä¼å¯¼è´crashï¼å½crashçæ£åçæ¶ï¼å¾æå¯è½ä¸ä¼å¨0xb7éè¿ï¼
ããããçè³è°ç¨å æ é½å·²ç»è¢«åä¹±ï¼è®©ä½ æ ä»ä¸æãï¼åè§5.1 为ä»ä¹ç¨åºcrashæ¶è°ç¨å æ æ¯ä¹±çï¼
2. å®ä½åå¸å¨å¤ççæ¬çCrashé误
ããåå¸å¨å¤ç软件crashäºï¼å¾å¾ä¸å¥½è°è¯ï¼æ以ç®åå¾å¤è½¯ä»¶é½æâåéé误æ¥åâè¿ä¸åè½ã
ããå®ç°è¿ä¸åè½ä¸è¬å以ä¸å æ¥ï¼
ããa. 使ç¨SetUnhandledExceptionFilterå½æ°
ãããã使ç¨SetUnhandledExceptionFilter设置æé«ä¸çº§çå¼å¸¸å¤çå½æ°ï¼å½ç¨åºåºç°ä»»ä½æªå¤ççå¼å¸¸ï¼é½ä¼è§¦åä½ è®¾ç½®çå½æ°éãå ·ä½ä½¿ç¨å¯åç §msdnåemuleæºç ã
ããb. 使ç¨MiniDumpWriteDumpå½æ°
ããããå¨ä½ çå¼å¸¸å¤çå½æ°éï¼ä½¿ç¨MiniDumpWriteDumpæé误信æ¯åæç¹å®æ ¼å¼çæ件ãå ·ä½ä½¿ç¨å¯åç §msdnåemuleæºç ã
ããc. åéé误æ¥å
ããããéç¨ä¸ç§å½¢å¼æ第äºæ¥äº§ççé误æ¥å(.dmp)æ件åéç»ä½ æå®çå°æ¹ã
ããd. æ¥çé误æ¥å
ããããè¿éä»ç»ç¨vcæ¥çé误æ¥åçæ¹æ³ï¼è¿å¯ä»¥ç¨windows debug toolsè¿ä¸ªå·¥å ·çï¼æ¹æ³è§5.2 使ç¨windows debug toolsæ¥ç.dmpæ件(é误æ¥å)
ãããã
ããããæ¥çé误æ¥åéè¦æä¸æ ·ä¸è¥¿ï¼å¯¹åºreleaseçç代ç ï¼å½æ¶ç¼è¯releaseçæ产çç.exeå.pdbæ件ãï¼è¿ä¸¤ä¸ªæ件é½å¨ç¼è¯çè¾åºç®å½éãï¼æ以å½ç¨åºåå¸æ¶ï¼è¦ä¿çä¸è¿ä¸¤ä¸ªæ件ã
ããããæ.dmpï¼é误æ¥åæ件ï¼,源码zookeeper源码下载 .pdb, .exe. 代ç ï¼å¨åä¸ç®å½ä¸ï¼ç¨vcæå¼.dmp æ件ã
ããããæF5è¿è¡ï¼ç¨åºå³å°è¾¾crashæ¶çç¶æï¼å¯ä»¥å¯¹å ¶è¿è¡ç¸åºçåæã
ãããã
ããä¸ç¹è¡¥å ï¼å½æ²¡æâåéé误æ¥åâçåè½ï¼ææ¯æ¤åè½å¤±æï¼ä»¥è´å¼¹åºäºwindowsçâåéé误æ¥åâç对è¯æ¡ãè¿æ¶å ¶å®ä¹æ¯æé误æ¥åçï¼ä¸è¬å¨C:Documents and Settingsç¨æ·åLocal SettingsTempéçä¸ä¸ª.dmpæ件(ä¸è¬åªæä¸ä¸ª.dmp)
3. å°æå·§
ãã3.1 æ ¹æ®ç¨åºå°åæ¾å°ä»£ç ä½ç½®
ããããå¯æå¦ä¸æ¥éª¤ï¼
ããããa. 使ç¨åºå¤äºåæ¢ç¶æãï¼æ¯å¦ç¨åºè¿è¡æ¶ï¼å¨vcéæCtrl+Alt+Breakï¼æ设æç¹ä½¿ç¨åºåä¸ï¼
ããããb. åæ¢å°æ±ç¼ç¶æãï¼Ctrl+Fï¼
ããããc. å¨å°åæ è¾å ¥ç¨åºå°åï¼å车ã
ããããd. å¯æCtrl+Fåå代ç 模å¼ã
ãã3.2 æ ¹æ®æ¶æ¯å¼æ¥ç对åºçwindowsæ¶æ¯
ããããå¨vcççè§çªå£éè¾å ¥âæ¶æ¯å¼,wmâå³å¯çå°å¯¹åºçæ¶æ¯ã
ãã3.3 æ¥çGetLastErrorè¿åå¼
ããããå¨vcççè§çªå£éè¾å ¥â@err,hrâï¼å³å¯çå°LastErroråå ¶è§£éã
ãã3.4 å¨ä»£ç ä¸æåç¨åº
ããããå¨debugçä¸å¯ä»¥å¨ä»£ç ä¸å ä¸âAfxDebugBreak()ï¼â以æåç¨åºãreleaseçå¯ä½¿ç¨ â_asm int 3;â
4. ç¼ç¨å°è¦ç¤º
ãã4.1 æ ç¨IsBadPtrç³»åå½æ°
ããããå½ä½¿ç¨IsBadReadPtr, IsBadWritePtr, IsBadCodePträ¸ç³»åå½æ°æ¶è¦æ³¨æï¼è¿ä¸ç±»å½æ°å¯è½å¹¶ä¸è½è¾¾å°ä½ ææ³è¦çæå¾ã
ããããæ¯å¦ä¸é¢ç代ç ï¼ä¸¤ä¸ªè¿åé½æ¯falseã
代ç
char *p = new char[];
bool b;
b = IsBadReadPtr(p+, 1);
delete[] p;
char *q = new char[];
b = IsBadReadPtr(p, 1);
ããããæ以åå¿å¨ç¨åºä¸ä»¥IsBadPtrå½æ°æ¥å¤ææ¯å¦å¯ä»¥å¯¹è¿ä¸ªæéè¿è¡æä½ãè¿äºå½æ°åªè½å¨è°è¯ä¸ä½¿ç¨ï¼ææ¯ä½ ç¡®åçç¥éè¿äºå½æ°çè¿åå¼è¡¨ç¤ºçæ¯ä»ä¹æä¹çæ¶åã
ãã4.2 æ ç¨catch(...)
ãããã为äºé²æ¢ç¨åºcrashææ¯è§£å³ä¸ä¸ªä¸æç½çcrashæ¶ï¼å¤§å®¶å¾å®¹ææ³å°ä¸ä¸ª try{ }catch(...){ }æ¥è§£å³é®é¢ã
ããããç确大é¨åæ¶é´è¿æ ·ä¸ä¼åºé®é¢äºï¼ä½è¿ä¸ªtry-catchå¾æå¯è½éèæå¨tryéé¢çé误ï¼èå½ç±æ¤é误å¼èµ·å ¶ä»é误æ¶ï¼å°±å¾é¾è¿½è¸ªå°è¿ä¸ªé®é¢äºã
ããããæ以建议尽éå°ç¨catch(...)ï¼å¦æç¥éæä¸å代ç ä¼æåºå¼å¸¸ï¼åºè¯¥ç¨ç¡®åçåæ³ãæ¯å¦catch(CFileException *e), catch(int e)ççã
5. éå½
ãã5.1 为ä»ä¹ç¨åºcrashæ¶è°ç¨å æ æ¯ä¹±ç
ããããå½å å被åä¹±æ¶ç¨åºå¾æå¯è½åºç°å¾é¾å®ä½çcrashï¼æ¯å¦è°ç¨å æ æ¯ä¹±çï¼æèµ°å°ä¸åå¨ç代ç éãè¿é举ä¸ä¾
代ç
class CA
{
public:
CA(){ }
~CA(){ }
virtual f(){ }
};
void show()
{
printf("shown");
}
int main()
{
// 对å被å建å é¤
CA *p = new CA;
delete p;
// ä¸äºæ£å¸¸çæä½
int *q = new int;
int codeAddress = (int)show;
*q = (int)&codeAddress;
// è°ç¨è¢«å é¤ç对åï¼ç¨åºæå¯è½æ§è¡å°ä»»ä½å°æ¹ã
p->f();
}
ããããä¸é¢ä»£ç çç»æä¼èµ°å°show()éæ¾ç¤ºåºshowï¼è¿è·ç¼è¯ç¯å¢æå ³ï¼vcä¸æµè¯ç»ææ¯è¿æ ·ï¼ãå¦æä½ äºè§£c++çvtableæºå¶å°±æç½è¿æ¯æä¹åäºã
ããããå¦æä¸æç½ä¹æ²¡å ³ç³»ï¼æä¸é¢è¯´ä¸ªå¤§æ¦ã
ããããé¦å CA对象被å建å被å é¤ãå¦ææ¤æ¶è°ç¨p->f()å¤åä¼crashã
ãããã第äºå代ç å¯è§ä¸ºä¸äºæ£å¸¸çæä½ï¼newäºä¸ä¸ªqï¼ç¶å对å®è¿è¡äºä¸äºèµå¼ã
ããããå¦æä½ ä¸æç½vtableæºå¶ï¼é£ä½ åªè¦ç¥éï¼æåä¸è¡ç âp->f();âä¼æ§è¡åéqææåçåéææåçåéææ 示çå°åãï¼è¿é没æéåï¼æ¯ä¸¤ä¸ªâææåçåéâï¼
ããããè¿éæâå¿å°åè¯âçç»è¿ä¸ªå¼èµä¸äºä¸ä¸ªåæ³çå½æ°å°åshowãä½å®é ç¨åºä¸qææåçåéæå¯è½æ¯ä»»æå¼ï¼å®åæåçåéå°±æ´æ¯ä»»æå¼äºã
ããããé£ç¨åºå°±ä¸ç¥éè·åªéå»äºãå¦æè¿ä¸ªå¼è¿äºç¦»è°±ï¼é£ç®ä½ è¿æ°å¥½ï¼ç¨åºä¼ç«å³crashï¼èä½ å°±ç¥éé误ä½ç½®å¨åªäºãä½è®¨äººåçæ¯ï¼å®æå¯è½æ¯ä¸ä¸ªåæ³å°åï¼é£ç¨åºå°±ç»§ç»èµ°ä¸å»ï¼
ããããä½è¿æ©ä¼crashï¼å¹¶ä¸è°ç¨å æ é¢ç®å ¨éï¼åå çµæ¶å°âè°ç¨å æ çæ¨å¯¼âçé®é¢è¿éå°±ä¸å¤è¯´äºï¼ï¼
ããããå°æ¶å°±æ ¹æ¬æ ä»ç¥éåæ¥æ¯è°ç¨äºè¢«å é¤çp对象è导è´çã
ãã5.2 使ç¨Debugging tools for windowsæ¥ç.dmpæ件(é误æ¥å)
ããããa. åå¤å¥½ç¨åºå¯¹åºç代ç ï¼exeæ件ï¼pdbæ件ï¼ç¼è¯æ¶å¨ç¼è¯è¾åºç®å½éï¼
ããããb. å®è£ WinDbg
ããããc. å¨winDbgéæSymbolç®å½è®¾å¨.pdbæå¨ç®å½ï¼Imageç®å½è®¾å¨.exeæå¨ç®å½ï¼codeç®å½è®¾å°ä»£ç ç®å½ã
ããããd. æå¼.dmpæ件
ããããe. è¾å ¥å½ä»¤.ecxrãï¼æ¤å½ä»¤ä½¿ç¯å¢åå°å´©æºæ¶çç¶æï¼
ããããf. æå¼è°ç¨å æ (ALT + F6)æ¥çCrashçä½ç½®
ããããg. è¿è¡åæ
ç®ä»
ããï¼FinalCheckè½æ£æµåºçé误å表è§éå½1ï¼
ããBoundsCheckeræ¯ä¸ä¸ªå¾å¼ºå¤§çè°è¯å·¥å ·ãè¿éåªç®åä»ç»å¦ä½ç¨å®çFinalCheck模å¼å®ä½æ¯è¾é¾å®ä½çé误ã
FinalCheck模å¼ç®åæ¥è¯´å°±æ¯BoundsCheckerå¨ä½ ç代ç éå ä¸äºè¯æ代ç æ¥æ£æ¥å¹³æ¶æ¯è¾é¾æ¥åºçå åè¶çï¼é误çæé使ç¨çã
ä¸è¿ä»åºç代价就æ¯ç¨åºè·èµ·æ¥ä¼æ¯è¾æ ¢ï¼æ以å¨ä¸ç¨æ¶æ好æ¯æFinalCheck模å¼å ³æãç¹å«æ¯åå¸åã
å±å¹åè¯
âé¼ æ å±å¹åè¯âææ¯æ¯å¨çµååå ¸ä¸å¾å°å¹¿æ³å°åºç¨çï¼å¦åéå©æ¹åéå±±è¯é¸ç软件ï¼è¿ä¸ªææ¯çä¼¼ç®åï¼å ¶å®å¨WINDOWSç³»ç»ä¸å®ç°å´æ¯é常å¤æçï¼æ»çæ¥è¯´æ两ç§å®ç°æ¹å¼ï¼
第ä¸ç§ï¼éç¨æªè·å¯¹é¨åGDIçAPIè°ç¨æ¥å®ç°,å¦TextOut,TextOutAçã
第äºç§ï¼å¯¹æ¯ä¸ªè®¾å¤ä¸ä¸æ(DC)åä¸åCopy,并è·è¸ªææä¿®æ¹ä¸ä¸æ(DC)çæä½ã
第äºç§æ¹æ³æ´å¼ºå¤§,ä½å ¼å®¹æ§ä¸å¥½ï¼è第ä¸ç§æ¹æ³ä½¿ç¨çæªè·WindowsAPIçè°ç¨ï¼è¿é¡¹ææ¯ç强大å¯è½è¿è¿è¶ åºäºæ¨çæ³è±¡ï¼æ¯«ä¸å¤¸å¼ ç说ï¼å©ç¨WindowsAPIæ¦æªææ¯ï¼ä½ å¯ä»¥æ¹é æ´ä¸ªæä½ç³»ç»ï¼äºå®ä¸å¾å¤å¤æå¼Windowsä¸æå¹³å°å°±æ¯è¿ä¹å®ç°çï¼èè¿é¡¹ææ¯ä¹æ£æ¯è¿ç¯æç« ç主é¢ã
æªWindowsAPIçè°ç¨ï¼å ·ä½ç说æ¥ä¹å¯ä»¥å为两ç§æ¹æ³ï¼
第ä¸ç§æ¹æ³éè¿ç´æ¥æ¹åWinAPI å¨å åä¸çæ åï¼åµå ¥æ±ç¼ä»£ç ï¼ä½¿ä¹è¢«è°ç¨æ¶è·³è½¬å°æå®çå°åè¿è¡æ¥æªè·ï¼ç¬¬äºç§æ¹æ³åæ¹åIATï¼Import Address Table è¾å ¥å°å表ï¼ï¼éå®åWinAPIå½æ°çè°ç¨æ¥å®ç°å¯¹WinAPIçæªè·ã
第ä¸ç§æ¹æ³çå®ç°è¾ä¸ºç¹çï¼èä¸å¨Winãä¸é¢æ´æé¾åº¦ï¼è¿æ¯å 为è½ç¶å¾®è½¯è¯´WINçAPIåªæ¯ä¸ºäºå ¼å®¹æ§æä¿çä¸æ¥ï¼ç¨åºååºè¯¥å°½å¯è½å°è°ç¨ä½çAPI,å®é ä¸æ ¹æ¬å°±ä¸æ¯è¿æ ·ï¼WIN 9Xå é¨ç大é¨åä½APIç»è¿åæ¢è°ç¨äºååçä½APIï¼ä¹å°±æ¯è¯´æ们éè¦å¨æ¦æªçå½æ°ä¸åµå ¥ä½æ±ç¼ä»£ç ï¼
æ们å°è¦ä»ç»çæ¯ç¬¬äºç§æ¦æªæ¹æ³ï¼è¿ç§æ¹æ³å¨WinãåNTä¸é¢è¿è¡é½æ¯è¾ç¨³å®ï¼å ¼å®¹æ§è¾å¥½ãç±äºéè¦ç¨å°å ³äºWindowsèæå åç管çãæç ´è¿ç¨è¾¹çå¢ãååºç¨ç¨åºçè¿ç¨ç©ºé´ä¸æ³¨å ¥ä»£ç ãPEï¼Portable Executableï¼æä»¶æ ¼å¼åIATï¼è¾å ¥å°å表ï¼çè¾åºå±çç¥è¯ï¼æ以æ们å 对æ¶åå°çè¿äºç¥è¯å¤§æ¦å°åä¸ä¸ªä»ç»ï¼æåä¼ç»åºæ¦æªé¨åçå ³é®ä»£ç ã
å 说Windowsèæå åç管çãWindows9Xç»æ¯ä¸ä¸ªè¿ç¨åé äº4GBçå°å空é´ï¼å¯¹äºNTæ¥è¯´ï¼è¿ä¸ªæ°åæ¯2GBï¼ç³»ç»ä¿çäº2GBå° 4GBä¹é´çå°å空é´ç¦æ¢è¿ç¨è®¿é®ï¼èå¨Win9Xä¸ï¼2GBå°4GBè¿é¨åèæå°å空é´å®é ä¸æ¯ç±ææçWINè¿ç¨æå ±äº«çï¼è¿é¨åå°å空é´å è½½äºå ±äº«Win DLLãå åæ å°æ件åVXDãå å管çå¨åæ件系ç»ç ï¼Win9Xä¸è¿é¨å对äºæ¯ä¸ä¸ªè¿ç¨é½æ¯å¯è§çï¼è¿ä¹æ¯Win9Xæä½ç³»ç»ä¸å¤å¥å£®çåå ã
Win9Xä¸ä¸ºä½æä½ç³»ç»ä¿çäº0å°4MBçå°å空é´ï¼èå¨4MBå°2GBä¹é´ä¹å°±æ¯Winè¿ç¨ç§æçå°å空é´ï¼ç±äº æ¯ä¸ªè¿ç¨çå°å空é´é½æ¯ç¸å¯¹ç¬ç«çï¼ä¹å°±æ¯è¯´ï¼å¦æç¨åºæ³æªè·å ¶å®è¿ç¨ä¸çAPIè°ç¨ï¼å°±å¿ é¡»æç ´è¿ç¨è¾¹çå¢ï¼åå ¶å®çè¿ç¨ä¸æ³¨å ¥æªè·APIè°ç¨ç代ç ï¼è¿é¡¹å·¥ä½æ们交ç»é©åå½æ°ï¼SetWindowsHookExï¼æ¥å®æï¼å ³äºå¦ä½å建ä¸ä¸ªå å«ç³»ç»é©åçå¨æé¾æ¥åºï¼ãçµèé«ææå¿ãå·²ç»æè¿ä¸é¢ä»ç»äºï¼è¿éå°±ä¸èµè¿°äºã
ææç³»ç»é©åçå½æ°å¿ é¡»è¦å¨å¨æåºéï¼è¿æ ·çè¯ï¼å½è¿ç¨éå¼ææ¾å¼è°ç¨ä¸ä¸ªå¨æåºéçå½æ°æ¶ï¼ç³»ç»ä¼æè¿ä¸ªå¨æåºæ å°å°è¿ä¸ªè¿ç¨çèæå°å空é´éï¼è¿ä½¿å¾DLLæ为è¿ç¨çä¸é¨åï¼ä»¥è¿ä¸ªè¿ç¨ç身份æ§è¡ï¼ä½¿ç¨è¿ä¸ªè¿ç¨çå æ ï¼ä¹å°±æ¯è¯´å¨æé¾æ¥åºä¸ç代ç 被é©åå½æ°æ³¨å ¥äºå ¶å®GUIè¿ç¨çå°å空é´ï¼éGUIè¿ç¨ï¼é©åå½æ°å°±æ è½ä¸ºåäºï¼ï¼å½å å«é©åçDLLæ³¨å ¥å ¶å®è¿ç¨åï¼å°±å¯ä»¥åå¾æ å°å°è¿ä¸ªè¿ç¨èæå åéçå个模åï¼EXEåDLLï¼çåºå°åï¼å¦ï¼
HMODULE hmodule=GetModuleHandle(âMypro.exeâ);
å¨MFCç¨åºä¸,æ们å¯ä»¥ç¨AfxGetInstanceHandle()å½æ°æ¥å¾å°æ¨¡åçåºå°åãEXEåDLL被æ å°å°èæå å空é´çä»ä¹å°æ¹æ¯ç±å®ä»¬çåºå°åå³å®çãå®ä»¬çåºå°åæ¯å¨é¾æ¥æ¶ç±é¾æ¥å¨å³å®çãå½ä½ æ°å»ºä¸ä¸ªWinå·¥ç¨æ¶ï¼VCï¼ï¼é¾æ¥å¨ä½¿ç¨ç¼ºççåºå°å0xãå¯ä»¥éè¿é¾æ¥å¨çBASEé项æ¹å模åçåºå°åãEXEé常被æ å°å°èæå åç0xå¤ï¼DLLä¹éä¹æä¸åçåºå°åï¼é常被æ å°å°ä¸åè¿ç¨çç¸åçèæå°å空é´å¤ã
ç³»ç»å°EXEåDLLåå°ä¸å¨æ å°å°èæå å空é´ä¸ï¼å®ä»¬å¨å åä¸çç»æä¸ç£çä¸çéææ件ç»ææ¯ä¸æ ·çãå³PE (Portable Executable) æä»¶æ ¼å¼ãæ们å¾å°äºè¿ç¨æ¨¡åçåºå°å以åï¼å°±å¯ä»¥æ ¹æ®PEæ件çæ ¼å¼ç©·ä¸¾è¿ä¸ªæ¨¡åçIMAGE_IMPORT_DESCRIPTORæ°ç»ï¼ççè¿ç¨ç©ºé´ä¸æ¯å¦å¼å ¥äºæ们éè¦æªè·çå½æ°æå¨çå¨æé¾æ¥åºï¼æ¯å¦éè¦æªè·âTextOutAâï¼å°±å¿ é¡»æ£æ¥âGdi.dllâæ¯å¦è¢«å¼å ¥äºã
说å°è¿éï¼æ们æå¿ è¦ä»ç»ä¸ä¸PEæ件çæ ¼å¼ï¼å¦å³å¾ï¼è¿æ¯PEæä»¶æ ¼å¼ç大è´æ¡å¾ï¼æåé¢æ¯æ件头ï¼æ们ä¸å¿ çä¼ï¼ä»PE File Optional Headeråé¢å¼å§ï¼å°±æ¯æ件ä¸å个段ç说æï¼è¯´æåé¢ææ¯çæ£ç段æ°æ®ï¼èå®é ä¸æä»¬å ³å¿çåªæä¸ä¸ªæ®µï¼é£å°±æ¯â.idataâ段ï¼è¿ä¸ªæ®µä¸å å«äºææçå¼å ¥å½æ°ä¿¡æ¯ï¼è¿æIATï¼Import Address Tableï¼çRVAï¼Relative Virtual Addressï¼å°åã
说å°è¿éï¼æªè·WindowsAPIçæ´ä¸ªåçå°±è¦çç¸å¤§ç½äºãå®é ä¸ææè¿ç¨å¯¹ç»å®çAPIå½æ°çè°ç¨æ»æ¯éè¿PEæ件çä¸ä¸ªå°æ¹æ¥è½¬ç§»çï¼è¿å°±æ¯ä¸ä¸ªè¯¥æ¨¡å(å¯ä»¥æ¯EXEæDLL)çâ.idataâ段ä¸çIATè¾å ¥å°å表ï¼Import Address Tableï¼ãå¨é£éææææ¬æ¨¡åè°ç¨çå ¶å®DLLçå½æ°ååå°åãå¯¹å ¶å®DLLçå½æ°è°ç¨å®é ä¸åªæ¯è·³è½¬å°è¾å ¥å°å表ï¼ç±è¾å ¥å°å表å跳转å°DLLçæ£çå½æ°å ¥å£ã
å ·ä½æ¥è¯´ï¼æ们å°éè¿IMAGE_IMPORT_DESCRIPTORæ°ç»æ¥è®¿é®â.idataâ段ä¸å¼å ¥çDLLçä¿¡æ¯ï¼ç¶åéè¿IMAGE_THUNK_DATAæ°ç»æ¥é对ä¸ä¸ªè¢«å¼å ¥çDLL访é®è¯¥DLLä¸è¢«å¼å ¥çæ¯ä¸ªå½æ°çä¿¡æ¯ï¼æ¾å°æ们éè¦æªè·çå½æ°ç跳转å°åï¼ç¶åæ¹ææ们èªå·±çå½æ°çå°åâ¦â¦å ·ä½çåæ³å¨åé¢çå ³é®ä»£ç ä¸ä¼æ详ç»ç讲解ã
讲äºè¿ä¹å¤åçï¼ç°å¨è®©æ们åå°âé¼ æ å±å¹åè¯âçä¸é¢ä¸æ¥ãé¤äºAPIå½æ°çæªè·ï¼è¦å®ç°âé¼ æ å±å¹åè¯âï¼è¿éè¦åä¸äºå ¶å®çå·¥ä½ï¼ç®åç说æ¥ï¼å¯ä»¥æä¸ä¸ªå®æ´çåè¯è¿ç¨å½çº³æ以ä¸å 个æ¥éª¤ï¼
1ï¼ å®è£ é¼ æ é©åï¼éè¿é©åå½æ°è·å¾é¼ æ æ¶æ¯ã
使ç¨å°çAPIå½æ°ï¼SetWindowsHookEx
2ï¼ å¾å°é¼ æ çå½åä½ç½®ï¼åé¼ æ ä¸ççªå£åéç»æ¶æ¯ï¼è®©å®è°ç¨ç³»ç»å½æ°éç»çªå£ã
使ç¨å°çAPIå½æ°ï¼WindowFromPointï¼ScreenToClientï¼InvalidateRect
3ï¼ æªè·å¯¹ç³»ç»å½æ°çè°ç¨ï¼åå¾åæ°ï¼ä¹å°±æ¯æ们è¦åçè¯ã
对äºå¤§å¤æ°çWindowsåºç¨ç¨åºæ¥è¯´ï¼å¦æè¦åè¯ï¼æ们éè¦æªè·çæ¯âGdi.dllâä¸çâTextOutAâå½æ°ã
æ们å ä»¿ç §TextOutAå½æ°åä¸ä¸ªèªå·±çMyTextOutAå½æ°ï¼å¦ï¼
BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)
{
// è¿éè¿è¡è¾åºlpszStringçå¤ç
// ç¶åè°ç¨æ£ççTextOutAå½æ°
}
æè¿ä¸ªå½æ°æ¾å¨å®è£ äºé©åçå¨æè¿æ¥åºä¸ï¼ç¶åè°ç¨æ们æåç»åºçHookImportFunctionå½æ°æ¥æªè·è¿ç¨å¯¹TextOutAå½æ°çè°ç¨ï¼è·³è½¬å°æ们çMyTextOutAå½æ°ï¼å®æ对è¾åºå符串çææã
HookImportFunctionçç¨æ³ï¼
HOOKFUNCDESC hd;
PROC pOrigFuns;
hd.szFunc="TextOutA";
hd.pProc=(PROC)MyTextOutA;
HookImportFunction (AfxGetInstanceHandle(),"gdi.dll",&hd,pOrigFuns);
ä¸é¢ç»åºäºHookImportFunctionçæºä»£ç ï¼ç¸ä¿¡è¯¦å°½ç注éä¸å®ä¸ä¼è®©æ¨è§å¾ç解æªè·å°åºæ¯æä¹å®ç°çå¾é¾ï¼Ok,Letâs Goï¼
///////////////////////////////////////////// Begin ///////////////////////////////////////////////////////////////
#include <crtdbg.h>
// è¿éå®ä¹äºä¸ä¸ªäº§çæéçå®
#define MakePtr(cast, ptr, AddValue) (cast)((DWORD)(ptr)+(DWORD)(AddValue))
// å®ä¹äºHOOKFUNCDESCç»æ,æ们ç¨è¿ä¸ªç»æä½ä¸ºåæ°ä¼ ç»HookImportFunctionå½æ°
typedef struct tag_HOOKFUNCDESC
{
LPCSTR szFunc; // The name of the function to hook.
PROC pProc; // The procedure to blast in.
} HOOKFUNCDESC , * LPHOOKFUNCDESC;
// è¿ä¸ªå½æ°çæµå½åç³»ç»æ¯å¦æ¯WindowNT
BOOL IsNT();
// è¿ä¸ªå½æ°å¾å°hModule -- å³æ们éè¦æªè·çå½æ°æå¨çDLL模åçå¼å ¥æ述符(import descriptor)
PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule);
// æ们ç主å½æ°
BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule,
LPHOOKFUNCDESC paHookFunc, PROC* paOrigFuncs)
{
/////////////////////// ä¸é¢ç代ç æ£æµåæ°çæææ§ ////////////////////////////
_ASSERT(szImportModule);
_ASSERT(!IsBadReadPtr(paHookFunc, sizeof(HOOKFUNCDESC)));
#ifdef _DEBUG
if (paOrigFuncs) _ASSERT(!IsBadWritePtr(paOrigFuncs, sizeof(PROC)));
_ASSERT(paHookFunc.szFunc);
_ASSERT(*paHookFunc.szFunc != '\0');
_ASSERT(!IsBadCodePtr(paHookFunc.pProc));
#endif
if ((szImportModule == NULL) || (IsBadReadPtr(paHookFunc, sizeof(HOOKFUNCDESC))))
{
_ASSERT(FALSE);
SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// çæµå½å模åæ¯å¦æ¯å¨2GBèæå å空é´ä¹ä¸
// è¿é¨åçå°åå åæ¯å±äºWinè¿ç¨å ±äº«ç
if (!IsNT() && ((DWORD)hModule >= 0x))
{
_ASSERT(FALSE);
SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);
return FALSE;
}
// æ¸ é¶
if (paOrigFuncs) memset(paOrigFuncs, NULL, sizeof(PROC));
// è°ç¨GetNamedImportDescriptor()å½æ°,æ¥å¾å°hModule -- å³æ们éè¦
// æªè·çå½æ°æå¨çDLL模åçå¼å ¥æ述符(import descriptor)
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = GetNamedImportDescriptor(hModule, szImportModule);
if (pImportDesc == NULL)
return FALSE; // è¥ä¸ºç©º,å模åæªè¢«å½åè¿ç¨æå¼å ¥
// ä»DLL模åä¸å¾å°åå§çTHUNKä¿¡æ¯,å 为pImportDesc->FirstThunkæ°ç»ä¸çåå§ä¿¡æ¯å·²ç»
// å¨åºç¨ç¨åºå¼å ¥è¯¥DLLæ¶è¦çä¸äºææçå¼å ¥ä¿¡æ¯,æ以æ们éè¦éè¿åå¾pImportDesc->OriginalFirstThunk
// æéæ¥è®¿é®å¼å ¥å½æ°åçä¿¡æ¯
PIMAGE_THUNK_DATA pOrigThunk = MakePtr(PIMAGE_THUNK_DATA, hModule,
pImportDesc->OriginalFirstThunk);
// ä»pImportDesc->FirstThunkå¾å°IMAGE_THUNK_DATAæ°ç»çæé,ç±äºè¿éå¨DLL被å¼å ¥æ¶å·²ç»å¡«å äº
// ææçå¼å ¥ä¿¡æ¯,æ以çæ£çæªè·å®é ä¸æ£æ¯å¨è¿éè¿è¡ç
PIMAGE_THUNK_DATA pRealThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc->FirstThunk);
// 穷举IMAGE_THUNK_DATAæ°ç»,寻æ¾æ们éè¦æªè·çå½æ°,è¿æ¯æå ³é®çé¨å!
while (pOrigThunk->u1.Function)
{
// åªå¯»æ¾é£äºæå½æ°åèä¸æ¯åºå·å¼å ¥çå½æ°
if (IMAGE_ORDINAL_FLAG != (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG))
{
// å¾å°å¼å ¥å½æ°çå½æ°å
PIMAGE_IMPORT_BY_NAME pByName = MakePtr(PIMAGE_IMPORT_BY_NAME, hModule,
pOrigThunk->u1.AddressOfData);
// å¦æå½æ°å以NULLå¼å§,è·³è¿,继ç»ä¸ä¸ä¸ªå½æ°
if ('\0' == pByName->Name[0])
continue;
// bDoHookç¨æ¥æ£æ¥æ¯å¦æªè·æå
BOOL bDoHook = FALSE;
// æ£æ¥æ¯å¦å½åå½æ°æ¯æ们éè¦æªè·çå½æ°
if ((paHookFunc.szFunc[0] == pByName->Name[0]) &&
(strcmpi(paHookFunc.szFunc, (char*)pByName->Name) == 0))
{
// æ¾å°äº!
if (paHookFunc.pProc)
bDoHook = TRUE;
}
if (bDoHook)
{
// æ们已ç»æ¾å°äºæè¦æªè·çå½æ°,é£ä¹å°±å¼å§å¨æå§
// é¦å è¦åçæ¯æ¹åè¿ä¸åèæå åçå åä¿æ¤ç¶æ,让æ们å¯ä»¥èªç±åå
MEMORY_BASIC_INFORMATION mbi_thunk;
VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
_ASSERT(VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
PAGE_READWRITE, &mbi_thunk.Protect));
// ä¿åæ们æè¦æªè·çå½æ°çæ£ç¡®è·³è½¬å°å
if (paOrigFuncs)
paOrigFuncs = (PROC)pRealThunk->u1.Function;
// å°IMAGE_THUNK_DATAæ°ç»ä¸çå½æ°è·³è½¬å°åæ¹å为æ们èªå·±çå½æ°å°å!
// 以åææè¿ç¨å¯¹è¿ä¸ªç³»ç»å½æ°çææè°ç¨é½å°æ为对æ们èªå·±ç¼åçå½æ°çè°ç¨
pRealThunk->u1.Function = (PDWORD)paHookFunc.pProc;
// æä½å®æ¯!å°è¿ä¸åèæå åæ¹ååæ¥çä¿æ¤ç¶æ
DWORD dwOldProtect;
_ASSERT(VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
mbi_thunk.Protect, &dwOldProtect));
SetLastError(ERROR_SUCCESS);
return TRUE;
}
}
// 访é®IMAGE_THUNK_DATAæ°ç»ä¸çä¸ä¸ä¸ªå ç´
pOrigThunk++;
pRealThunk++;
}
return TRUE;
}
// GetNamedImportDescriptorå½æ°çå®ç°
PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule)
{
// æ£æµåæ°
_ASSERT(szImportModule);
_ASSERT(hModule);
if ((szImportModule == NULL) || (hModule == NULL))
{
_ASSERT(FALSE);
SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);
return NULL;
}
// å¾å°Dosæ件头
PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) hModule;
// æ£æµæ¯å¦MZæ件头
if (IsBadReadPtr(pDOSHeader, sizeof(IMAGE_DOS_HEADER)) ||
(pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE))
{
_ASSERT(FALSE);
SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);
return NULL;
}
// åå¾PEæ件头
PIMAGE_NT_HEADERS pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader->e_lfanew);
// æ£æµæ¯å¦PEæ åæ件
if (IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) ||
(pNTHeader->Signature != IMAGE_NT_SIGNATURE))
{
_ASSERT(FALSE);
SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);
return NULL;
}
// æ£æ¥PEæ件çå¼å ¥æ®µ(å³ .idata section)
if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
return NULL;
// å¾å°å¼å ¥æ®µ(å³ .idata section)çæé
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, pDOSHeader,
pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
// 穷举PIMAGE_IMPORT_DESCRIPTORæ°ç»å¯»æ¾æ们éè¦æªè·çå½æ°æå¨ç模å
while (pImportDesc->Name)
{
PSTR szCurrMod = MakePtr(PSTR, pDOSHeader, pImportDesc->Name);
if (stricmp(szCurrMod, szImportModule) == 0)
break; // æ¾å°!ä¸æ循ç¯
// ä¸ä¸ä¸ªå ç´
pImportDesc++;
}
// å¦æ没ææ¾å°,说ææ们寻æ¾ç模å没æ被å½åçè¿ç¨æå¼å ¥!
if (pImportDesc->Name == NULL)
return NULL;
// è¿åå½æ°ææ¾å°ç模åæ述符(import descriptor)
return pImportDesc;
}
// IsNT()å½æ°çå®ç°
BOOL IsNT()
{
OSVERSIONINFO stOSVI;
memset(&stOSVI, NULL, sizeof(OSVERSIONINFO));
stOSVI.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
BOOL bRet = GetVersionEx(&stOSVI);
_ASSERT(TRUE == bRet);
if (FALSE == bRet) return FALSE;
return (VER_PLATFORM_WIN_NT == stOSVI.dwPlatformId);
}
/////////////////////////////////////////////// End //////////////////////////////////////////////////////////////////////
ä¸ç¥éå¨ä¹åï¼æå¤å°æåå°è¯è¿å»å®ç°âé¼ æ å±å¹åè¯âè¿é¡¹å 满äºææçææ¯ï¼ä¹åªæå°è¯è¿çæåæè½ä½ä¼å°å ¶é´çä¸æï¼å°¤å ¶å¨æ¢ç´¢APIå½æ°çæªè·æ¶ï¼æ头çå ç¯èµæ没æä¸ç¯æ¯æ¶åå°å ³é®ä»£ç çï¼éè¦çå°æ¹é½æ¯ä¸ç¬ä»£è¿ï¼MSDNæ´æ¯æ¾å¾èç½èæ åï¼ä¹ä¸ç¥éé¤äºIMAGE_IMPORT_DESCRIPTORåIMAGE_THUNK_DATAï¼å¾®è½¯è¿éèäºå¤å°ç§å¯ï¼å¥½å¨ç¡¬ç头ç®è¿æ¯æå®ç»æ»å äºï¼å¸æè¿ç¯æç« å¯¹å¤§å®¶è½ææ帮å©ã