ESETã«ããFinFisherãµã€ããŒã¹ãã€æŽ»åã®åæåŸã2017幎å€ã«ç¶æ³ã¯å€ããå§ããŸããã ãã®èª¿æ»ã®éçšã§ã ã€ã³ã¿ãŒããããµãŒãã¹ãããã€ããŒã®è¢«å®³è ã䟵害ããæ»æãç¹å®ããŸããã

Malvariã®åæãéå§ãããšããWindowsããŒãžã§ã³ã§ã®FinFisherã®åæã«å¯Ÿæããããã®å¯Ÿçãå æããããšã«äž»ãªåªåãè²»ããããŸããã é«åºŠãªé£èªåãšç¬èªã®ä»®æ³åã®çµã¿åããã«ãããFinFisherãã¹ãã³ã°ããã»ã¹ã¯éåžžã«å°é£ã«ãªããŸãã
ãã®ã¬ã€ãã§ã¯ãFinFisheråæããã»ã¹ã§åŠãã ããšãå ±æããŸãã FinFisherä»®æ³ãã·ã³ã®åæã«é¢ãããã³ãã«å ããŠããã®ã¬ã€ãã¯ãä»®æ³ãã·ã³å šäœãã€ãŸããã€ããªã³ãŒãã§æ€åºããããœãããŠã§ã¢ã®ä¿è·ã«äœ¿çšãããç¬èªã®ä»®æ³ãã·ã³ã䜿çšããä¿è·ãç解ããã®ã«åœ¹ç«ã¡ãŸãã
ãŸããFinFisher for Androidã®ããŒãžã§ã³ãåæããŸããããã®ä¿è·ã¡ã«ããºã ã¯ããªãŒãã³ã¢ã¯ã»ã¹LLVMé£èªåããŒã«ã«åºã¥ããŠããŸãã Windowsã®ããŒãžã§ã³ã¡ã«ããºã ã»ã©è€éã§ããããããªãã®ã§ããã®ã¬ã€ãã§ã¯èª¬æããŸããã
ãã®ã¬ã€ãããæ å ±ã»ãã¥ãªãã£ã®ç 究è ããŠã€ã«ã¹åæè ãFinFisherã®ããŒã«ãšæŠè¡ãç解ãããã®è åšãã顧客ãä¿è·ããã®ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã
å解察ç
IDA Proã§FinFisherãµã³ãã«ãéããšãã¡ã€ã³æ©èœã«ãå解ã§ãããæåã®é²åŸ¡çã«å¯Ÿæããããã®ã·ã³ãã«ã ãå¹æçãªæ¹æ³ããããŸãã
FinFisherã¯ãéã¢ã»ã³ããªã«å¯ŸããŠäžè¬çãªææ³ã䜿çšããŸãã1ã€ã®ç¡æ¡ä»¶ãžã£ã³ãåœä»€ã2ã€ã®è£å®çãªæ¡ä»¶ä»ãé·ç§»ã«çœ®ãæããããšã«ãããå®è¡ã®é²è¡ãé ããŸãã ãããã¯åãé·ç§»ãã€ã³ããæããŠãããããå®è¡ãããé·ç§»ã«é¢ä¿ãªããã³ãŒãã®å®è¡é åºã¯å€ãããŸããã æ¡ä»¶ä»ããžã£ã³ãã®åŸã¯ãæå³ã®ãªãã³ãŒããã€ãã«ãªããŸãã éåžžã®æ¡ä»¶äžã§ã¯ãéäœæ¥é åãèªèã§ããããã®ãŽãã®å解äœæ¥ãç¶ç¶ãããããéã¢ã»ã³ãã©ãŒãæ··ä¹±ãããããã«èšèšãããŠããŸãã
ç¹ã«ããã®ãã«ãŠã§ã¢ã¯ãã®ææ³ã䜿çšããŸãã ç§ãã¡ã調æ»ããã»ãšãã©ã®ãã«ãŠã§ã¢ã¯ããã®æ¹æ³ãç¹å®ã®åæ°äœ¿çšããŠããŸãã ãã ããFinFisherã¯åã³ãã³ãã®åŸã«ãã®ããªãã¯ãé©çšããŸãã
ãã®ä¿è·ã¯éã¢ã»ã³ãã©ã«å¯ŸããŠéåžžã«å¹æçã§ãããå€ãã®ã³ãŒããé©åã«ããã»ã¹ãééããªãããã«æ··ä¹±ãããŸãã ãããŠããã¡ãããIDA Proã®ã°ã©ãã£ãã¯ã¢ãŒãã¯äœ¿çšã§ããªããªããŸãã æåã®ã¿ã¹ã¯ã¯ããã®ä¿è·ãåãé€ãããšã§ãã
ã³ãŒãã¯æããã«æåã§ã¯é£èªåãããŠããŸããããèªåããŒã«ã®å©ããåããŠã移è¡ã³ãã³ãã®ãã¹ãŠã®ãã¢ã§ç¹å®ã®ãã¿ãŒã³ã芳å¯ããŠããŸãã
ãžã£ã³ããã¢ã«ã¯2ã€ã®ç°ãªãã¿ã€ãããããŸããã€ã³ãã³ãã32ãããã®å éšãžã£ã³ããšã€ã³ãã³ãã8ãããã®çãé·ç§»ã§ãã
äž¡æ¹ã®æ¡ä»¶ä»ãå éšé·ç§»ïŒDWORDã¯é·ç§»ã€ã³ãã³ãïŒã®ãªãã¬ãŒã·ã§ã³ã³ãŒãã¯ããã€ã0x0Fã§å§ãŸãã2çªç®ã®ãã€ãã¯0x8ã§ããïŒ äž¡æ¹ã®é·ç§»åœä»€ã§ããããã¯1ãããã ãç°ãªããŸãã ããã¯ãçžè£çãªé·ç§»ã®x86 OSãªãã¬ãŒã·ã§ã³ã³ãŒããæ°å€çã«é£ç¶ããŠãããšããäºå®ã«ãããã®ã§ãã ããšãã°ããã®é£èªåã¹ããŒã ã¯ãåžžã«JEãšJNEïŒãªãã³ãŒã0x0F 0x84ããã³0x0F 0x85ïŒãJPãšJNPïŒãªãã³ãŒã0x0F 0x8Aããã³0x0F 0x8BïŒãªã©ããã¢ã«ããŸãã
ãããã®ãªãã³ãŒãã®åŸã«ââãé·ç§»ãè¡ãããã€ã³ãã³ããå®çŸ©ãã32ãããåŒæ°ããããŸãã äž¡æ¹ã®åœä»€ã®ãµã€ãºã¯6ãã€ãã§ããããã2ã€ã®é£ç¶ããé·ç§»ã®ã€ã³ãã³ãã¯æ£ç¢ºã«6ç°ãªããŸãïŒå³1ãåç §ïŒã

å³1.æ¯å2ã€ã®æ¡ä»¶ä»ãå éšé·ç§»ãç¶ãã³ãã³ãã®ã¹ã¯ãªãŒã³ã·ã§ãã
ããšãã°ã次ã®ã³ãŒãã䜿çšããŠãããã2ã€ã®é£ç¶ããé·ç§»ãæ€åºã§ããŸãã
def is_jump_near_pair(addr): jcc1 = Byte(addr+1) jcc2 = Byte(addr+7) # ? if Byte(addr) != 0x0F || Byte(addr+6) != 0x0F: return False # 2 ? if (jcc1 & 0xF0 != 0x80) || (jcc2 & 0xF0 != 0x80): return False # ? if abs(jcc1-jcc2) != 1: return False # ? dst1 = Dword(addr+2) dst2 = Dword(addr+8) if dst1-dst2 != 6 return False return True
çãé·ç§»ã®é£èªå解é€ã¯åæ§ã®èãæ¹ã«åºã¥ããŠãããå®æ°ã®ã¿ãç°ãªããŸãã
çãæ¡ä»¶åå²ã®ãªãã³ãŒãã¯0x7ïŒã§ããã®åŸã«1ãã€ãïŒé·ç§»ã®ã€ã³ãã³ãïŒãç¶ããŸãã ãããã£ãŠãåã³2ã€ã®é£ç¶ããæ¡ä»¶ä»ãå éšé·ç§»ãæ¢ããŠããããªãã¬ãŒã·ã§ã³ã³ãŒã0x7ïŒ;ãå¿ èŠã§ãã ã€ã³ãã³ã; 0x7ïŒ Â±1; ã€ã³ãã³ã-2ã æåã®ãªãã³ãŒãã®åŸã1ã€ã®ãã€ããããã2ã€ã®é£ç¶ããé·ç§»ã§2ã ãç°ãªããŸãïŒãããäž¡æ¹ã®åœä»€ã®ãµã€ãºã§ãïŒïŒå³2ïŒã

å³2.æ¯å2ã€ã®çãæ¡ä»¶ä»ãé·ç§»ãç¶ãã³ãã³ãã®äŸ
ããšãã°ããã®ã³ãŒãã䜿çšããŠã2ã€ã®æ¡ä»¶ä»ãã·ã§ãŒããžã£ã³ããæ€åºã§ããŸãã
def is_jcc8(b): return b&0xF0 == 0x70 def is_jump_short_pair(addr): jcc1 = Byte(addr) jcc2 = Byte(addr+2) if not is_jcc8(jcc1) || not is_jcc8(jcc2): return False if abs(jcc2âjcc1) != 1: return False dst1 = Byte(addr+1) dst2 = Byte(addr+3) if dst1 â dst2 != 2: return False return True
ãããã®æ¡ä»¶åå²ã®ãã¢ã®1ã€ãèŠã€ããåŸããããã䜿çšããŠã³ãŒãã®é£èªåã解é€ããæåã®æ¡ä»¶åå²ãç¡æ¡ä»¶ã«ãïŒå éšé·ç§»ãã¢ã«0xE9ãªãã³ãŒãã䜿çšããã·ã§ãŒããžã£ã³ããã¢ã«0xEBã䜿çšïŒãæ®ãã®ãã€ãã空ã®åœä»€ïŒ0x90ïŒã§åããŸã
def patch_jcc32(addr): PatchByte(addr, 0x90) PatchByte(addr+1, 0xE9) PatchWord(addr+6, 0x9090) PatchDword(addr+8, 0x90909090) def patch_jcc8(addr): PatchByte(addr, 0xEB) PatchWord(addr+2, 0x9090)
ããã2ã€ã®ç¶æ³ã«å ããŠãé·ç§»ã®ãã¢ãçãã¿ã€ããšå éšã¿ã€ããã€ãŸãç°ãªãã¿ã€ãã§æ§æãããå ŽåããããŸãã ããããããã¯å°æ°ã®å Žæã§ããèŠã€ãããªããããFinFisherãµã³ãã«ã§ã¯ãããæåã§ä¿®æ£ã§ããŸãã
ãããã®æ¿å ¥ç©ã䜿çšããŠãIDA Proã¯æ°ããã³ãŒãããç解ããå§ãããã£ãŒããäœæããæºåãã§ããŠããŸãïŒãŸãããŸãã¯ã»ãŒæºåãã§ããŠããŸãïŒã çµäºç¹ãè¿œå ãããã€ãŸãããŒãã«é·ç§»äœçœ®ãå²ãåœãŠããã£ãŒãäžã§é·ç§»ã³ãã³ããšäžèŽããããã«ãããã«æ¹åããå¿ èŠãããå ŽåããããŸãã ãã®ããã«ãPython IDAé¢æ°
append_func_tail
䜿çšã§ããŸãã
éã¢ã»ã³ãã©ã®éåžžã®åäœã劚ããããªãã¯ãåé¿ããæåŸã®æé ã¯ãé¢æ°å®çŸ©ãä¿®æ£ããããšã§ãã 移è¡åŸã®ã³ãã³ãã
push ebp
ã§ããå ŽåããããŸãããã®å ŽåãIDA Proã¯ïŒèª€ã£ãŠïŒãããé¢æ°ã®éå§ãšèŠãªããããã«å¿ããŠæ°ããå®çŸ©ãéå§ããŸãã ãã®å Žåãé¢æ°å®çŸ©ãåé€ããæ£ãããšã³ããªãäœæããããã«æ«å°Ÿãè¿œå ããå¿ èŠããããŸãã
ãã®ããã«ããŠãå解ã«å¯Ÿããæåã®FinFisherä¿è·ãåé€ããŸãã
FinFisherä»®æ³ãã·ã³
第1ã¬ãã«ã®ä¿è·ã®é£èªå解é€ã«æåãããšãã¡ã€ã³æ©èœãéããŸãããã®äž»ãªç®çã¯ãç¹å¥ã«äœæãããä»®æ³ãã·ã³ãèµ·åããããã«ãã€ããŒãã䜿çšããŠãã€ãã³ãŒãã解éããããšã§ãã
éåžžã®å®è¡å¯èœãã¡ã€ã«ãšã¯ç°ãªããå éšã«ä»®æ³ãã·ã³ãæã€å®è¡å¯èœãã¡ã€ã«ã¯ãããã»ããµåœä»€ãçŽæ¥å®è¡ãã代ããã«ãä»®æ³åãããåœä»€ã»ããã䜿çšããŸãã ä»®æ³åãããã³ãã³ãã¯ãç¬èªã®æ§é ãæã¡ããã€ãã³ãŒããã¢ã³ãããŒãžãã·ã³ã³ãŒãã«å€æããªãä»®æ³ããã»ããµã«ãã£ãŠå®è¡ãããŸãã ãã®ä»®æ³ããã»ããµã¯ããã€ãã³ãŒãïŒããã³ä»®æ³åœä»€ïŒãšåæ§ã«ãä»®æ³ãã·ã³ãããã°ã©ã ãã人ã«ãã£ãŠæ±ºå®ãããŸãïŒå³3ïŒã
ã¯ããã«ãä»®æ³ãã·ã³ã®ããç¥ãããäŸã®1ã€ãJava VMã§ãããšè¿°ã¹ãŸããã ãã ãããã®å Žåãä»®æ³ãã·ã³ã¯ãã€ããªã³ãŒãå ã«ãããããããã§ã¯ãªããŒã¹ãšã³ãžãã¢ãªã³ã°ããä¿è·ããããã®ä»®æ³ãã·ã³ã«çŽé¢ããŠããŸãã VMProtectãCode Virtualizerãªã©ã®æåãªåçšä»®æ³ãã·ã³ä¿è·ããããŸãã
FinFisherã¹ãã€ãŠã§ã¢ã¯ãœãŒã¹ããã³ã³ãã€ã«ãããçæããããã€ããªã¯ã¢ã»ã³ããªã¬ãã«ã®ä»®æ³ãã·ã³ã«ãã£ãŠä¿è·ãããŸãã ä¿è·ããã»ã¹ã§ã¯ããœãŒã¹ãã€ããªãã¡ã€ã«ã®åœä»€ãä»®æ³åœä»€ã«å€æãããã€ãã³ãŒããšä»®æ³ããã»ããµãå«ãæ°ãããã€ããªãã¡ã€ã«ãäœæããŸãã ãœãŒã¹ãã€ããªããã®ãã€ãã£ãåœä»€ã¯å€±ãããŸãã ä¿è·ãããä»®æ³åããããµã³ãã«ã¯ãä¿è·ãããŠããªããµã³ãã«ãšåãåäœãããå¿ èŠããããŸãã
ä»®æ³ãã·ã³ã§ä¿è·ããããã€ããªãã¡ã€ã«ãåæããã«ã¯ã次ã®ãã®ãå¿ èŠã§ãã
- ä»®æ³CPUã®åæ
- ãã®éæšæºã®ä»®æ³CPUçšã«ç¬èªã®éã¢ã»ã³ãã©ãŒãäœæãããã€ãã³ãŒãã解æããŸã
- ãªãã·ã§ã³ïŒéã¢ã»ã³ãã«ãããã³ãŒãããã€ããªãã¡ã€ã«ã«ã³ã³ãã€ã«ããä»®æ³ãã·ã³ãåãé€ããŸãã
æåã®2ã€ã®ã¿ã¹ã¯ã«ã¯å€ãã®æéãããããæåã®ã¿ã¹ã¯ã¯éåžžã«è€éã«ãªãå¯èœæ§ããããŸãã åvm_handlerãã³ãã©ãŒã®åæãšãã¬ãžã¹ã¿ãŒãã¡ã¢ãªãŒã¢ã¯ã»ã¹ãåŒã³åºããªã©ã®è»¢éæ¹æ³ã®ç解ãå«ãŸããŸãã

å³3.ä»®æ³CPUã«ãã£ãŠè§£éããããã€ãã³ãŒã
çšèªãšå®çŸ©
ä»®æ³ãã·ã³ã®åã ã®éšåãå®çŸ©ããããã®æšæºã¯ãããŸããã ãããã£ãŠããã®ãã¯ã€ãããŒããŒã§åç §ããããã€ãã®çšèªãå®çŸ©ããŸãã
- ä»®æ³ãã·ã³ïŒvmïŒâä»®æ³CPUã vm_dispatcherãvm_startãvm_handlersãå«ãŸããŸã
- vm_start-åæå; ããã§ã¡ã¢ãªã®å²ãåœãŠãšåŸ©å·åããã»ã¹ãè¡ãããŸã
- ãã€ãã³ãŒãïŒ pcodeãšãåŒã°ããŸãïŒ-åŒæ°ä»ãã®ä»®æ³ãªãã³ãŒãvm_instructionsã¯ããã«ä¿åãããŸã
- vm_dispatcher-ä»®æ³ãªãã³ãŒããåŒã³åºããŠãã³ãŒãããŸãã åºæ¬çã«ã vm_handlersã®å®è¡ã®æºåãããŸã
- vm_handler - vm_instructionã®å®è£ ã 1ã€ã®vm_handlerã®å®è¡ã¯ã1ã€ã®vm_instructionã®å®è¡ãæå³ããŸã
- ã€ã³ã¿ãŒããªã¿ãŒïŒ vm_loopãšãåŒã°ããïŒ -vm_dispatcher + vm_handlers-ä»®æ³CPU
- ä»®æ³ãªãã³ãŒã-ãã€ãã£ããªãã³ãŒãã®é¡äŒŒç©
- vm_context ïŒ vm_structure ïŒ-ã€ã³ã¿ãŒããªã¿ãŒã䜿çšããå éšæ§é
- vi_params - vm_contextæ§é å ã®æ§é ã vm_handlerã䜿çšããä»®æ³ã³ãã³ãã®ãã©ã¡ãŒã¿ãŒã vm_opcodeãšåŒæ°ãå«ã
ãã€ãã³ãŒãã解éããããã»ã¹ã§ãä»®æ³ãã·ã³ã¯ä»®æ³ã¹ã¿ãã¯ãšåäžã®ä»®æ³ã¬ãžã¹ã¿ã䜿çšããŸãã
- vm_stack-ä»®æ³ãã·ã³ã䜿çšãããã€ãã£ãã¹ã¿ãã¯ã®é¡äŒŒç©
- vm_register-ãã®ä»®æ³ãã·ã³ã§äœ¿çšããããã€ãã£ãã¬ãžã¹ã¿ã®é¡äŒŒç©ã 以äžãtmp_REGãšåŒã°ããŸã
- vm_instruction-ä»®æ³ãã·ã³ã®éçºè ã«ãã£ãŠå®çŸ©ãããããŒã ã ã³ãã³ãã®æ¬äœïŒå®è£ ïŒã¯ã vm_handlerã«ãã£ãŠåŒã³åºãããŸã
以äžã®ã»ã¯ã·ã§ã³ã§ã¯ãä»®æ³ãã·ã³ã®èŠçŽ ãæè¡çãªè©³çŽ°ã§èª¬æããããããåæããæ¹æ³ã説æããŸãã
Malvariã®ã¡ã€ã³é¢æ°ã®é£èªåãããã°ã©ãã£ã«ã«è¡šçŸã¯ãåæåãšvm_startããã³ã€ã³ã¿ãŒããªã¿ãŒïŒ vm_dispatcher + vm_handlers ïŒãšåŒã°ããä»ã®2ã€ã®3ã€ã®éšåã§æ§æãããŠããŸãã
åæåã³ã³ããŒãã³ãã¯ããã€ãã³ãŒãã®ãšã³ããªãã€ã³ããšããŠè§£éã§ãããã®ã«äžæã®èå¥åãèšå®ããã¹ã¿ãã¯ã«ããã·ã¥ããŸãã 次ã«ã vm_startéšåãžã®ç§»è¡ãã€ãŸãä»®æ³ãã·ã³èªäœã®åæåããã»ã¹ãè¡ãããŸãã ãã€ãã³ãŒãã埩å·åãããå¶åŸ¡ãvm_dispatcherã«æž¡ãããŸããvm_dispatcherã¯ããã€ãã³ãŒãã®ä»®æ³åœä»€ãµã€ã¯ã«ãéå§ãã vm_handlersã䜿çšããŠãããã解éããŸãã
Vm_dispatcherã¯pushaã³ãã³ãã§å§ãŸãã
jmp dword ptr [eax+ecx*4]
ã³ãã³ãïŒãŸãã¯åæ§ïŒãã€ãŸã察å¿ããvm_handlerãžã®ç§»è¡ã§çµãããŸãã
Vm_start
第1ã¬ãã«ã®é£èªå解é€åŸã«äœæãããã°ã©ãã£ãã¯ã¢ãã«ãå³4ã«ç€ºããŸããvm_startã«é¢é£ããéšåã¯ãã€ã³ã¿ãŒããªã¿ãŒã®åæã«ãšã£ãŠããã»ã©éèŠã§ã¯ãããŸããã ãã ããä»®æ³ãã·ã³å šäœã®å®è£ ãä»®æ³ãã©ã°ãä»®æ³ã¹ã¿ãã¯ãªã©ã®äœ¿çšæ¹æ³ãšç®¡çæ¹æ³ãç解ãããšåœ¹ç«ã¡ãŸãã 2çªç®ã®éšåã§ããvm_disperscherãšvm_handlersã¯ãåºç€ã§ãã

å³4. vm_startããã³vm_dispatcherã®ã°ã©ãã£ã«ã«è¡šçŸ
vm_startã®åŒã³åºã㯠ãã¡ã€ã³ãå«ãã»ãŒãã¹ãŠã®é¢æ°ããè¡ãããŸãã
åŒã³åºãé¢æ°ã¯åžžã«ä»®æ³èå¥åãããã·ã¥ããŠããã vm_startã«ç§»è¡ããŸã ã åä»®æ³ããŒã ã«ã¯ç¬èªã®ä»®æ³èå¥åããããŸãã ãã®äŸã§ã¯ãã¡ã€ã³é¢æ°ããã®å®è¡ãéå§ãããä»®æ³ãšã³ããªãã€ã³ãã®èå¥åã¯0x21CD0554ã§ãïŒå³5ïŒã

å³5. vm_startã¯ã119åã®ä»®æ³åãããé¢æ°ã®ããããããåŒã³åºãããŸãã
察å¿ããé¢æ°ã®æåã®ä»®æ³ã³ãã³ãã®èå¥åãåŒæ°ãšããŠäžããããŸãã
ãã®éšåã§ã¯ãã»ãšãã©ã®ã³ãŒãã¯vm_dispatcherã®æºåã«å°å¿µããŠããŸããäž»ã«ãã€ãã³ãŒããšã€ã³ã¿ãŒããªã¿ãŒå šäœã®ã¡ã¢ãªã®å²ãåœãŠã§ãã æãéèŠãªã³ãŒãã¯æ¬¡ã®ããšãè¡ããŸãã
- ãã€ãã³ãŒããšããã€ãã®å€æ°ã®å²ãåœãŠãèªã¿åããæžã蟌ã¿ãå®è¡ã®èš±å¯ãæã€1 MBã®ã¡ã¢ãªã
- çŸåšã®ã¿ã¹ã¯ãã§ãŒã³ã®ä»®æ³ãã·ã³ã®ããŒã«ã«å€æ°ã«å¯ŸããŠåã解å床ã§0x10000ãã€ããå²ãåœãŠãããŠããã®ã¯vm_stackã§ãã
- XOR埩å·åïŒæä»çORïŒã 埩å·åãããã³ãŒãã¯aPLibãšããŠè§£åãããŸãã ãµã³ãã«ã®åŸ©å·åããã»ã¹ã§ã¯ãXOR dwordããŒã®ãããã«å€æŽãããããŒãžã§ã³ã䜿çšããŠããŸãã æåã®6ã€ã®DWORDãã¹ãããããããŒã䜿çšããŠæ®ãã®5ã€ã®DWORDã«XORãé©çšããŸãã 以äžã¯ããã»ã¹ã¢ã«ãŽãªãºã ã§ãïŒä»¥éãXOR埩å·åã³ãŒããšåŒã³ãŸãïŒïŒ
int array[6]; int key; for (i = 1; i < 6; i++) { array[i] ^= key; }
- ãã€ãã³ãŒãã解åããaPLibããã»ã¹ãåŒã³åºããŸãã ãã®åŸãä»®æ³ãªãã³ãŒãã¯æå·åããããŸãŸã«ãªããŸãïŒå³6ïŒã
ä»®æ³ãªãã³ãŒãã®æºåïŒã¹ããã1ã3ã4 ïŒã¯æåã«äžåºŠã ãå®è¡ããã以éã®vm_startã®å®è¡ã§ã¯ã¹ããããããŸããããã©ã°ãšã¬ãžã¹ã¿ã䜿çšããã³ãã³ãã®ã¿ãå®è¡ãããŸãã

å³6. vm_startããvm_dispatcherãŸã§ã®ãã¹ãŠã®ã³ãŒãã¯ã°ã«ãŒãåãããå®å ã«å¿ããŠååãä»ããããŸãã
FinFisheréèš³
ãã®éšåã«ã¯ããã¹ãŠã®vm_handlers ïŒFinFisherãµã³ãã«ã§ã¯34ïŒãå«ãvm_dispatcherãå«ãŸããä»®æ³ãã·ã³ãåæããã³/ãŸãã¯ä»®æ³åããããã®éèŠãªèŠçŽ ã§ãã ã€ã³ã¿ãŒããªã¿ãŒã¯ãã€ãã³ãŒããå®è¡ããŸãã
jmp dword ptr [eax+ecx*4]
ã³ãã³ãã¯ã34 åã®vm_handlersã®ããããã«ãžã£ã³ãããŸãã åvm_handlerã¯ã1ã€ã®ä»®æ³ãã·ã³ã³ãã³ããå®è£ ããŸãã vm_handlerã®ããããã®æ©èœãç解ããã«ã¯ ã vm_contextãšvm_dispatcherãåŠçããå¿ èŠããããŸãã
1. IDAã§ã°ã©ãã£ã«ã«æ§é ãäœæãã
é©åã«æ§é åããããã£ãŒããäœæãããšãã€ã³ã¿ãŒããªã¿ãŒãããããç解ã§ããŸãã vm_startãšvm_dispatcherã® 2ã€ã®éšåã«åããããšããå§ãããŸãã ã€ãŸã ãæåã®vm_dispatcherã³ãã³ãã§é¢æ°ã®éå§ã決å®ããå¿ èŠããããŸãã ãã®å Žåã vm_dispatcherã«ãã£ãŠåç §ãããvm_handlersèªäœã¯ãŸã ãããŸããã ãããã®ãã³ãã©ãŒãvm_dispatcherå³ã«æ¥ç¶ããã«ã¯ã次ã®é¢æ°ã䜿çšã§ããŸãã
AddCodeXref(addr_of_jmp_instr, vm_handler,XREF_USER|fl_JN)
æåŸã®vm_dispatcherã³ãã³ãã® vm_handlersãªã³ã¯ã®å é ã«è¿œå
AppendFchunk
æåŸã«è¿œå ãçæããŸã
åvm_handlerãã³ãã©ãŒããã£ã¹ãããã£ãŒé¢æ°ã«è¿œå ãããšãå³ã¯æ¬¡ã®å³7ã«ç€ºãããã«ãªããŸãã
2. Vm_dispatcher
ãã®éšåã¯ããã€ãã³ãŒãã®åŠçãšãã³ãŒããæ åœããŸãã 圌女ã¯æ¬¡ã®æé ãå®è¡ããŸãã
-
pusf
ããã³pusf
ãå®è¡ããŠãä»®æ³ã³ãã³ãã®åŸç¶ã®å®è¡ã®ããã«ä»®æ³ã¬ãžã¹ã¿ããã³ä»®æ³ãã©ã°ãæºåããŸã - ã¡ã¢ãªå ã®ããã°ã©ã ã¢ãã¬ã¹ãšã¢ãã¬ã¹vm_stackãååŸããŸã
- 次ã®vm_instructionã³ãã³ããšãã®åŒæ°ãå®çŸ©ãã24ãã€ãã®ãã€ãã³ãŒããèªã¿åããŸã
- åè¿°ã®XORããã·ãŒãžã£ã䜿çšããŠãã€ãã³ãŒãã埩å·åããŸã
- åŒæ°ãã°ããŒãã«å€æ°ã§ããå Žåããã€ãã³ãŒãã®åŒæ°ãšããŠã¡ã¢ãªå ã®ããã°ã©ã ã¢ãã¬ã¹ãè¿œå ããŸã
- 解èªããããã€ãã³ãŒãããä»®æ³ãªãã³ãŒãïŒ0ã33ã®ç¯å²ã®æ°åïŒãååŸããŸã
- ä»®æ³ãªãã³ãŒãã解éãã察å¿ããvm_handlerãã³ãã©ãŒã«ç§»è¡ããŸã
ã³ãã³ãã®vm_handlerãå®è¡ãããåŸãæåã®vm_dispatcherã³ãã³ãããéå§ããŠãåãã·ãŒã±ã³ã¹ãåŸç¶ã®ã·ãŒã±ã³ã¹ã«å¯ŸããŠç¹°ãè¿ãããŸãã vm_callãã³ãã©ãŒã®å Žåãå¶åŸ¡ã¯vm_startã«æž¡ãããŸã ïŒéä»®æ³åé¢æ°ãåŸã«ç¶ãå Žåãé€ã ïŒã

å³7. 34åãã¹ãŠã®vm_handlersãå«ãvm_dispatcherãã€ã¢ã°ã©ã ã
3. Vm_context
ãã®ããŒãã§ã¯ã vm_context - vm_dispatcherããã³åvm_handlerã®å®è¡ã«å¿ èŠãªãã¹ãŠã®æ å ±ãå«ãä»®æ³ãã·ã³ã䜿çšããæ§é ã«ã€ããŠèª¬æããŸãã
vm_dispatcherããã³vm_handlersã³ãŒãã®è©³çŽ°ãªèª¿æ»ã§ã¯ã
ebx+offset
ãåç §ããããŒã¿åŠçã³ãã³ããå«ãŸããŠããããšãããããŸããããã§ãoffsetã¯0x00ã0x50ã®æ°åã§ãã å³8ã§ã¯ãFinFisherãµã³ãã«ã®1ã€ã§vm_handler 0x05ã®äž»èŠéšåãã©ã®ããã«èŠãããã確èªã§ããŸãã

å³8. vm_handlersã®1ã€ã®ã¹ã¯ãªãŒã³ã·ã§ãã
ebxã¬ãžã¹ã¿ã¯ã vm_contextãšåŒã°ããæ§é äœãæããŸãã ãã®æ§é ãã©ã®ããã«äœ¿çšãããã®ãããã®ã¡ã³ããŒãäœã§ããã®ããããããäœãæå³ããã®ããã©ã®ããã«é©çšãããã®ããç解ããå¿ èŠããããŸãã ãã®åé¡ãåããŠè§£æ±ºããã«ã¯ã vm_contextãšãã®éšåã®äœ¿çšæ¹æ³ãæšæž¬ããå¿ èŠããããŸãã
äŸãšããŠã vm_dispatcherã®æåŸã«ããäžé£ã®ã³ãã³ããèŠãŠã¿ãŸãããã
movzx ecx, byte ptr [ebx+0x3C] // vm_handler jmp dword ptr [eax+ecx*4] // 34 vm_handlers
æåŸã®ã³ãã³ãã¯vm_handlerãžã®ç§»è¡ã§ããããšãããã£ãŠãããããecxã«ã¯ä»®æ³ãªãã³ãŒããå«ãŸããŠããããããã£ãŠ0x3C vm_structèŠçŽ ã¯ä»®æ³ãªãã³ãŒããåç §ããŠãããšçµè«ä»ããããšãã§ããŸãã
ãã1ã€ã®æ ¹æ ã®ãªãä»®å®ãããŠã¿ãŸãããã ã»ãšãã©ãã¹ãŠã®vm_handlerã®æåŸã«ã次ã®ã³ãã³ãããããŸãã
add dword ptr [ebx], 0x18.
åãvm_contextèŠçŽ ãvm_dispatcherã³ãŒãã§ä»¥åã«äœ¿çšãããŠããŸãã-vm_handlerã«ç§»è¡ããçŽå ã vm_dispatcherã¯ãæ§é èŠçŽ ããå¥ã®å ŽæïŒ
[ebx+38h]
ïŒã«24ãã€ããã³ããŒããçŸåšã®ãã€ãã³ãŒãã®äžéšãååŸããããã«XORã䜿çšããŠããã解èªããŸãã
ã€ãŸãã vm_context ïŒ
[ebx+0h]
ïŒèŠçŽ ãvm_instruction_pointerãã€ã³ã¿ãŒãšããŠã埩å·åãããäœçœ®ïŒ
[ebx+38h]
ãã
[ebx+50h]
ïŒãä»®æ³ã³ãã³ãã®IDããã®ä»®æ³ãªãã³ãŒããããã³åŒæ°ãšèŠãªãå§ããããšãã§ããŸãã ãã®æ§é å šäœã«vi_paramsãšããååãä»ããŸããã
äžèšã®æé ãå®äºãããããã°ããã°ã©ã ã䜿çšãããšãæ§é ã®å¯Ÿå¿ããèŠçŽ ã«å«ãŸããå€ãããããŸãã ã€ãŸã ããã¹ãŠã®vm_contextèŠçŽ ãå®çŸ©ã§ããŸãã
åæåŸãFinFisherã® vm_contextãšvi_paramsã®äž¡æ¹ã®æ§é ã埩å ã§ããŸãã
struct vm_context { DWORD vm_instruct_ptr; // DWORD vm_stack; // vm_stack DWORD tmp_REG; // ââ DWORD vm_dispatcher_loop; // vm_dispatcher DWORD cleanAndVMDispatchFn; // , vm_dispatcher, DWORD cleanUpDynamicCodeFn; // , vm_instr_ptr cleanAndVMDispatchFn DWORD jmpLoc1; // DWORD jmpLoc2; // vm_opcode â vm_instruction DWORD Bytecode_start; // DWORD DispatchEBP; DWORD ImageBase; // DWORDESP0_flags;// ( vm_code) DWORDESP1_flags;// DWORD LoadVOpcodesSectionFn; vi_params bytecode; // vm_handler, DWORD limitForTopOfStack; // }; struct vi_params { DWORD Virtual_instr_id; DWORD OpCode; // values 0 â 33 -> , DWORD Arg0; // 4 dword vm_handler DWORD Arg4; // DWORD Arg8; // DWORD ArgC; // };
4.ä»®æ³ã³ãã³ãã®äœ¿çš-vm_handlers
vm_handlerã®ããããã¯ã1ã€ã®ä»®æ³ãªãã³ãŒããã€ãŸã34ã®vm_handlersãã³ãã©ãŒããšã«æ倧34ã®ä»®æ³ãªãã³ãŒãã§åäœããŸãã 1ã€ã®vm_handlerã®å®è¡ã¯1ã€ã®vm_instructionã®å®è¡ãæå³ããããã vm_instructionãäœãè¡ãããå€æããã«ã¯ã察å¿ããvm_handlerãåæããå¿ èŠããããŸãã
vm_contextãåæ§ç¯ããebxã®ãã¹ãŠã®ã€ã³ãã³ãã«ååãä»ãããšãåè¿°ã®vm_handlerãèªã¿ããããªããŸãïŒå³9ãåç §ïŒã
ãã®é¢æ°ã®æåŸã«ã vm_instruction_pointerã§å§ãŸãã³ãã³ãã®ã·ãŒã±ã³ã¹ããããŸããããã¯24ãã€å¢å ããŸãã ã€ãŸã ãåvm_instructionã®vi_paramsæ§é äœã®ãµã€ãºã«ãã£ãŠå¢å ããŸãã ãã®ã·ãŒã±ã³ã¹ã¯ã»ãŒãã¹ãŠã®vm_handlerã®æåŸã§ç¹°ãè¿ããããããããã¯æšæºã®çµäºé¢æ°ã³ãŒãã§ããã vm_handlerèªäœã®æ¬äœã¯æ¬¡ã®ããã«ç°¡åã«èšè¿°ã§ãããšçµè«ä»ããŠããŸãã
mov [tmp_REG], Arg0
ãããã£ãŠããã®ä»®æ³ãã·ã³ã®æåã®ã³ãã³ããåæããŸãã:-)

å³9. vm_contextæ§é ã«æ¿å ¥ããåŸã®ä»¥åã®vm_handler
åæãããã³ãã³ãã®æäœã説æããããã«ãvi_paramsæ§é äœã次ã®ããã«èšå®ãããŠãããšä»®å®ããŸãã
struct vi_params { DWORD ID_of_virt_instr = , ; DWORD OpCode = 0x0C; DWORD Arg0 = 0x42; DWORD Arg4 = 0; DWORD Arg8 = 0; DWORD ArgC = 0; };
äžèšããã次ã®ã³ãã³ããå®è¡ãããŠããããšãããããŸãã
mov [tmp_REG], 0x42
ãã®æç¹ã§ã vm_instructionsã® 1ã€ãäœããããããã§ã«ç解ããŠããã¯ãã§ãã å®ç§ãªã¹ãããã¯ãéèš³è å šäœã®ä»äºã®ãã¢ã³ã¹ãã¬ãŒã·ã§ã³ãšããŠåœ¹ç«ã€ã¯ãã§ãã
ãã ãã 解æãããå°é£ãªvm_handlersãããã€ããããŸãã ãã®ä»®æ³ãã·ã³ã®æ¡ä»¶ä»ãé·ç§»ã¯ããã©ã°ã®å€æãã©ã®ããã«çºçããããç解ããã®ãããå°é£ã§ãã
åè¿°ã®ããã«ã vm_dispatcherã¯ããã€ãã£ãEFLAGSïŒ vm_codeããïŒãç¬èªã®ã¹ã¿ãã¯ã®å é ã«çœ®ãããšããå§ããŸãã ãããã£ãŠã察å¿ããé·ç§»ã®ãã³ãã©ãŒã¯ããããè¡ããã©ããã決å®ãããšãã«ãç¬èªã®ã¹ã¿ãã¯å ã®EFLAGSããã§ãã¯ããç¬èªã®é·ç§»ã¡ãœãããé©çšããŸãã å³10ã¯ãããªãã£ãã§ãã¯ãä»ããŠä»®æ³JNPïŒããªãã£ããªãå Žåã¯ãžã£ã³ãïŒãã³ãã©ãã©ã®ããã«é©çšããããã瀺ããŠããŸãã

å³10. JNP_handlerã®ã¹ã¯ãªãŒã³ã·ã§ãã
ä»ã®ä»®æ³æ¡ä»¶ä»ãé·ç§»ã®å Žåãããã€ãã®å åã確èªããå¿ èŠãããå ŽåããããŸã-ããšãã°ãä»®æ³åãããJBEïŒä»¥äžã®å Žåã¯ãžã£ã³ãïŒã®é·ç§»ã®çµæã¯ããã£ãªãŒãã©ã°ãšãŒããã©ã°ã®äž¡æ¹ã®å€ã«äŸåããŸãããåçã¯åãã§ãã
FinFisherä»®æ³ãã·ã³ã®34 åã®vm_handlersããã¹ãŠåæããåŸããã®ä»®æ³ã³ãã³ãã次ã®ããã«èšè¿°ã§ããŸãã

å³11. 34åãã¹ãŠã®vm_handlersãæã€vm_table
ããŒã¯ãŒãã tmp_REG ãã¯ãä»®æ³ãã·ã³ã䜿çšããä»®æ³ã¬ãžã¹ã¿ã vm_contex tæ§é å ã®äžæã¬ãžã¹ã¿ãæããã reg ãã¯ããã»ããµèªèº«ã®ã¬ãžã¹ã¿ãã€ãŸã eaxã
åæãããä»®æ³ãã·ã³ã®ã³ãã³ããèŠãŠã¿ãŸãããã ããšãã°ã case_3_vm_jccã¯ãæ¡ä»¶ä»ããŸãã¯ç¡æ¡ä»¶ã®ä»»æã®ããã»ããµãžã£ã³ãåœä»€ãå®è¡ã§ããæ±çšãžã£ã³ãåœä»€ãã³ãã©ã§ãã
æããã«ããã®ä»®æ³ãã·ã³ã¯ãã¹ãŠã®ããŒããŠã§ã¢ã³ãã³ããä»®æ³åããããã§ã¯ãããŸãããããã§ãäžèšã®ãªã¹ãïŒã±ãŒã¹4ããã³ã±ãŒã¹6ïŒã®ã³ãã³ãã圹ç«ã¡ãŸãã
ããã2ã€ã®vm_handlerã¯ãã³ãŒããçŽæ¥å®è¡ããããã«äœ¿çšãããŸãã ããããè¡ãããšã¯ãåŒæ°ãšããŠããã»ããµã³ãã³ããªãã³ãŒããèªã¿åããã³ãã³ããå®è¡ããããšã§ãã
ãŸãã vm_registersã¯åžžã«èªèº«ã®ã¹ã¿ãã¯ã®æäžäœã«ãããå®è¡å¯èœã¬ãžã¹ã¿ã®èå¥åã¯ä»®æ³ã³ãã³ãã®arg0ã®æåŸã®ãã€ãã«æ ŒçŽãããããšã«æ³šæããŠãã ãã ã 察å¿ããä»®æ³ã¬ãžã¹ã¿ã«ã¢ã¯ã»ã¹ããã«ã¯ã次ã®ã³ãŒãã䜿çšã§ããŸãã
def resolve_reg(reg_pos): stack_regs = ['eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi'] stack_regs.reverse() return stack_regs[reg_pos] reg_pos = 7 â (state[arg0] & 0x000000FF) reg = resolve_reg(reg_pos)
5.ç¬èªã®éã¢ã»ã³ãã©ãŒã®äœæ
ãã¹ãŠã®vm_instructionsãæ£ããåæããåŸããµã³ãã«åæãéå§ããåã«å®è¡ããå¿ èŠããããã1ã€ã®ã¹ããããæ®ã£ãŠããŸã-ãã€ãã³ãŒãçšã«ç¬èªã®éã¢ã»ã³ãã©ãŒãäœæããå¿ èŠããããŸãïŒæåã§è§£æãããšãµã€ãºãåé¡ã«ãªããŸãïŒã
åªåããããä¿¡é Œæ§ã®é«ãéã¢ã»ã³ãã©ãŒãäœæããããšã§ãåŸã§FinFisherä»®æ³ãã·ã³ãå€æŽããã³æŽæ°ããããšãã«èªåèªèº«ãæããŸãã次ã®ã³ãã³ããå®è¡ããvm_handler 0x0Cãã
å§ããŸãããã
mov [tmp_REG], reg
ãã®ã³ãã³ãã¯åŒæ°ã1ã€ã ãåããŸã-regãšããŠäœ¿çšãããç¬èªã®ã¬ãžã¹ã¿ã®èå¥åããã®èå¥åã¯
resolve_reg
ãããšãã°äžã®äŸã®ã³ãã³ãã䜿çšããŠãç¬èªã®ã¬ãžã¹ã¿ã®ååã§è¡šç€ºããå¿ èŠããããŸãã
ãã®vm_handlerãéã¢ã»ã³ãã«ããã«ã¯ã次ã®ã³ãŒãã䜿çšã§ããŸãã
def vm_0C(state, vi_params): global instr reg_pos = 7 â (vi_arams[arg0] & 0x000000FF) tmpinstr = âmov [tmp_REG], %sâ % resolve_reg(reg_pos) instr.append(tmpinstr) return
ç¹°ãè¿ããŸããã移è¡çšã®vm_handlersã¯ç解ããã®ãå°é£ã§ããé·ç§»ã®å Žåãvm_context.vi_params.Arg0ããã³vm_contextã³ã³ããŒãã³ããvi_params.Arg1ã¯ãé·ç§»ãçºçããã€ã³ãã³ããæ ŒçŽããŸãããã®ããžã£ã³ãã€ã³ãã³ããã¯ãå®éã«ã¯ãã€ãã³ãŒãã§ã€ã³ãã³ããããŠããŸããé·ç§»ãã³ãã©ã解æããã«ã¯ãé·ç§»é åã®ããŒã«ãŒãåé 眮ããå¿ èŠããããŸãã次ã®ã³ãŒããé©ããŠããŸãã
def computeLoc1(pos, vi_params): global instr jmp_offset = (vi_params[arg0] & 0x00FFFFFF) + (vi_params[arg1] & 0xFF000000) if jmp_offset < 0x7FFFFFFF: jmp_offset /= 0x18 # their increment by 0x18 is my increment by 1 else: jmp_offset = int((- 0x100000000 + jmp_offset) / 0x18) return pos+jmp_offset
æåŸã«ãç¹å¥ãªåŠçãå¿ èŠãªåŒæ°ã䜿çšããŠãã€ãã£ãã³ãã³ããå®è¡ããvm_handlerããããŸãããããè¡ãã«ã¯ãããšãã°ãªãŒãã³ã¢ã¯ã»ã¹ã®DistormããŒã«ãªã©ãç¬èªã®x86ã³ãã³ãçšã®éã¢ã»ã³ãã©ãŒãå¿ èŠã§ãã
ã³ãã³ãã®é·ãã¯vm_context.vi_params.OpCodeïŒ0x0000FF00ã«ä¿åãããŸããå®è¡çšã®ãã€ãã£ãã³ãã³ãã®ãªãã³ãŒãã¯ãåŒæ°ã«æ ŒçŽãããŸãããã€ãã£ãã³ãŒããå®è¡ããvm_handlerã解æããã«ã¯ã次ã®ã³ãŒãã䜿çšã§ããŸãã
def vm_04(vi_params, pos): global instr nBytes = vi_params[opCode] & 0x0000FF00 dyn_instr = pack(â<LLLLâ, vi_params[arg0], vi_params[arg4], vi_params[arg8], vi_params[argC])[0:nBytes] dec_instr = distorm3.Decode(0x0, dyn_instr, distorm3.Decode32Bits) tmpinstr = â%sâ % (dec_instr[0][2]) instr.append(tmpinstr) return
ãã®æç¹ã§ãåvm_handlersã解æããããã®ãã¹ãŠã®é¢æ°ãPythonã§äœæããŸããããã©ã³ãžã·ã§ã³çšã®é åãããŒã¯ããã³ãŒããåŒã³åºãåŸã®ä»®æ³ã³ãã³ãã®IDã決å®ããã³ãŒããªã©ãããããã¹ãŠã¯ãç¬èªã®éã¢ã»ã³ãã©ãäœæããããã«å¿ èŠã§ãã
ãã®ãã¹ãŠã®åŸããã€ãã³ãŒãã«ãã£ãŠé§åã§ããŸãã

å³12.解åããã³åŸ©å·åãããFinFisherãã€ãã³ãŒãã®äžéš
ããšãã°ãå³12ã«ç€ºããã€ãã³ãŒãããã次ã®åºåãååŸã§ããŸãã
mov tmp_REG, 0 add tmp_REG, EBP add tmp_REG, 0x10 mov tmp_REG, [tmp_REG] push tmp_REG mov tmp_REG, EAX push tmp_REG
6.ãã®ä»®æ³ãã·ã³ã®äœ¿çšãç解ãã
ãã¹ãŠã®ä»®æ³ãã³ãã©ãŒãåæããç¬èªã®ã«ã¹ã¿ã éã¢ã»ã³ãã©ãŒãæ§ç¯ããåŸãä»®æ³ã³ãã³ããå床èŠãŠãäœæã®åºæ¬çãªèãæ¹ãç解ã§ããŸãã
æåã«ãä»®æ³åä¿è·ãã¢ã»ã³ãã©ã¬ãã«ã§é©çšãããŠããããšãç解ããå¿ èŠããããŸããäœæè ã¯ãç¬èªã®ããŒã ãç¬èªã®ããè€éãªããŒã ã«å€æããç¹å¥ãªä»®æ³CPUã§å®è¡ããŸãããã®ããã«ãäžæçãªãã¬ãžã¹ã¿ãïŒtmp_REGïŒã䜿çšãããŸãã
ããã€ãã®äŸãèŠãŠããã®å€æãã©ã®ããã«æ©èœããããç解ã§ããŸããåã®äŸããä»®æ³ã³ãã³ããåããŸã-
mov tmp_REG, EAX push tmp_REG
-圌女ã¯èªåã®ããŒã ããå€èº«ããŸãã
push eax
ãä»®æ³åã䜿çšããå Žåãã¿ã€ã ã¹ãããã®äžæã¬ãžã¹ã¿ã䜿çšããŠãã³ãã³ããããè€éãªãã®ã«å€æŽããŸãã
å¥ã®äŸãæããŸãã
mov tmp_REG, 0 add tmp_REG, EBP add tmp_REG, 0x10 mov tmp_REG, [tmp_REG] push tmp_REG
ãããã®ä»®æ³åã³ãã³ãã«å€æããããã€ãã£ãã³ãã³ãã以äžã«ç€ºããŸãïŒregã¯ç¬èªã®ã¬ãžã¹ã¿ã®1ã€ã§ãïŒã
mov reg, [ebp+0x10] push reg
ãã ããäžé£ã®ã³ãã³ããä»®æ³åããæ¹æ³ã¯ããã ãã§ã¯ãããŸãããä»ã®ã¢ãããŒãã§ã¯ãä¿è·ã®ããã®ä»®æ³ãã·ã³ã®ä»ã®çšéããããŸããããšãã°ã1ã€ã§ã¯ãªãè€æ°ã®äžæã¬ãžã¹ã¿ã䜿çšããŠãNORæ°åŠããžãã¯ïŒäž¡æ¹ã®å ¥åãè² ã®å ŽåïŒã䜿çšããä»®æ³ãã·ã³ã«ããä¿è·ã®åçšå®è£ ããããŸãã
é çªã«ãFinFisherã¯ãããŸã§è¡ããããã¹ãŠã®èªç€ŸããŒã ã転æããŸããã§ããã以äžã®ãããªæ°åŠçãªã³ãã³ãã -ãããã®å€ãã¯ãä»®æ³åãããŠããŸãããããã€ãã¯ããã§ã¯ãªããããããªã
add
ã
imul
ãš
div
ããããã®ã³ãã³ããå ã®ãã€ããªã§ããå Žåãvm_handlerãä¿è·ããããã¡ã€ã«ã§åŠçããããã«ãç¬èªã®ã³ãã³ãã®å®è¡ãæ åœããŸããçºçããå¯äžã®å€æŽã¯ãEFLAGSãšãã®ç¬èªã®ã¬ãžã¹ã¿ãç¬èªã®ã³ãã³ãã®å®è¡çŽåã«ååŸãããå®è¡ã®å®äºåŸã«åé€ãããããšã§ããããã«ãããåããŒã ã®ä»®æ³åãåé¿ã§ããŸãã
ãã€ããªãä»®æ³ãã·ã³ã§ä¿è·ããããšã®é倧ãªæ¬ ç¹ã¯ãããã©ãŒãã³ã¹ãžã®æªåœ±é¿ã§ãã FinFisherä»®æ³ãã·ã³ã®å Žåãåvm_instructionïŒvm_dispatcher + vm_handlerãåŠçããããã«å®è¡ãããã³ãã³ãã®æ°ãã«ãŠã³ãããããšã«åºã¥ããŠãå éšã³ãŒãã®å Žåãããé床ãçŽ100åé ããšæŠç®ããŸãïŒ
ãããã£ãŠããã€ããªã®éžæãããéšåã®ã¿ãä¿è·ããããšã¯çã«ããªã£ãŠããŸããããã¯ãåæããFinFisherãµã³ãã«ã§ããããè¡ãããšãšãŸã£ããåãã§ãã
ããã«ãæ¢ã«è¿°ã¹ãããã«ãäžéšã®ä»®æ³ãã·ã³ãã³ãã©ãŒã¯ç¬èªã®é¢æ°ãçŽæ¥åŒã³åºãããšãã§ããŸãããã®çµæãä»®æ³ãã·ã³ä¿è·ã®ãŠãŒã¶ãŒïŒã€ãŸããFinFisherã®äœæè ïŒã¯ãã¢ã»ã³ãã©ãŒæ®µéã§ããã®å©ããåããŠä¿è·ããæ©èœã決å®ã§ããŸããããŒã¯ãããæ©èœã«ã€ããŠã¯ãããŒã ã¯ä»®æ³åãããŸããæ®ãã«ã€ããŠã¯ãå ã®é¢æ°ã¯å¯Ÿå¿ããä»®æ³ãã³ãã©ãŒã«ãã£ãŠåŒã³åºãããŸãããããã£ãŠããã€ããªãã¡ã€ã«ã®æãèå³æ·±ãéšåã¯ä¿è·ããããŸãŸã§ãããã³ãŒãã®å®è¡ã«ãããæéã¯çããªããŸãïŒå³13ïŒã

13. , FinFisher, ,
7. FinFisher
ããŒãµãŒãåŠçããå¿ èŠã®ãããã€ãã³ãŒãé·ã«å ããŠãFinFisherã®ãµã³ãã«ã«ã¯äœããã®ããã·ã³ã°ãããããšãèŠããŠããå¿ èŠããããŸããä¿è·ã«ã¯åãä»®æ³ãã·ã³ã䜿çšãããŸãããä»®æ³ãªãã³ãŒããšvm_handlerséã®å¯Ÿå¿ã®å®çŸ©ã¯åžžã«äžèŽãããšã¯éããŸããããããã¯ã©ã³ãã ã«ãã¢ã«ã§ããŸãïŒãããŠããããèµ·ãããŸãïŒããããã®ãã¢ã¯ãåæããFinFisherãµã³ãã«ããšã«ç°ãªããŸããã€ãŸãããã®ãµã³ãã«ã®0x5ä»®æ³ãªãã³ãŒãã®vm_handlerã¯ã³ãã³ããåŠçãã
mov [tmp_REG], arg0
å¥ã®ä¿è·ããããµã³ãã«ã§ã¯å¥ã®ä»®æ³ãªãã³ãŒãã«å²ãåœãŠãããšãã§ããŸãã
ãã®åé¡ã解決ããããã«ãåæãããvm_handlersã®ããããã«çœ²åã䜿çšã§ããŸããä»é²Aã®Python IDAã®ã¹ã¯ãªããã¯ãå³7ãããã€ã¢ã°ã©ã ãååŸããåŸã«é©çšã§ããŸãïŒãã®ããã¥ã¢ã«ã®æåã®ã»ã¯ã·ã§ã³ã§èª¬æããããã«ãjz / jnzé·ç§»ã®é£èªåãåé€ããããšãç¹ã«éèŠã§ãïŒãïŒãã€ããŒãªæ¹åã«ãããFinFisherã®æŽæ°ããŒãžã§ã³ã§vm_handlersãå€æŽãããå Žåããã®ã¹ã¯ãªããã䜿çšããŠçœ²åã埩å ããããšãã§ããŸããïŒ
åè¿°ã®ããã«ãFinFisherãµã³ãã«ã®æåã®vm_handlerã¯ãåæäžã«ééããJLãšã¯ç°ãªãå ŽåããããŸããµã³ãã«ã®çµæã«ãªããŸããããã¹ã¯ãªããã¯ãã¹ãŠã®vm_handlersãæ£ããæ¹æ³ã§æ±ºå®ããŸãã
8.ä»®æ³ãã·ã³ã䜿çšããªãéã¢ã»ã³ãã«ã³ãŒãã®ã³ã³ãã€ã«
å解ããŠããã€ãã®å€æŽãå ããåŸãã³ãŒããã³ã³ãã€ã«ã§ããŸããç§ãã¡ã¯ãä»®æ³ããŒã ãç¬èªã®ãã®ãšããŠäœ¿çšããŸãããã®çµæãä¿è·ãããŠããªãçŽç²ãªãã€ããªã³ãŒããååŸãããŸããvm_instructions
ã³ãã³ãã®ã»ãšãã©ã¯ãåçŽãªã³ããŒã§ã³ã³ãã€ã«ã§ããŸããããã¯ãéã¢ã»ã³ãã©ã®åºåã§ã¯ãåºæ¬çã«ã³ãã³ãããã€ãã£ãã³ãã³ãã®ããã«èŠããããã§ãããã ããäžéšã®ã»ã¯ã·ã§ã³ã¯ç¹å¥ãªæ¹æ³ã§å€æŽããå¿ èŠããããŸããâ¢tmp_REG-tmp_REGãã°ããŒãã«å€æ°ãšããŠå®çŸ©ãããããæ ŒçŽãããŠããã¢ãã¬ã¹ãéåç §ãããŠããå Žåã¯ã³ãŒããå€æŽããå¿ èŠããããŸããïŒx86ã³ãã³ãã»ããã§ã¯ãã°ããŒãã«å€æ°ã®ã¢ãã¬ã¹ãéåç §ããããšã¯ã§ããŸãããïŒããšãã°ãä»®æ³ãã·ã³ã«ã¯ä»®æ³ã³ãã³ããå«ãŸããŸã
mov tmp_REG, [tmp_REG]
次ã®ããã«æžãæããå¿ èŠããããŸãã
push eax mov eax, tmp_REG mov eax, [eax] mov tmp_REG, eax pop eax
â¢ãã©ã°-ä»®æ³ããŒã ã¯ãã©ã°ãå€æŽããŸããããç¬èªã®æ°åŠããŒã ãå€æŽããŸãããããã£ãŠãä»®æ³åããããã€ããªã®ä»®æ³æ°åŠåœä»€ã§ããããè¡ããªãããšãéèŠã§ããã€ãŸããåœä»€ãå®è¡ããåã«ãã©ã°ãä¿åããå®è¡ã®å®äºåŸã«ãã©ã°ã埩å ããå¿ èŠããããŸãã
â¢é·ç§»ãšåŒã³åºã-ããŒã«ãŒãä»®æ³ã³ãã³ãïŒé·ç§»ïŒãŸãã¯é¢æ°ïŒåŒã³åºãïŒã®é åã«ç§»åããå¿ èŠããããŸãã
â¢APIé¢æ°åŒã³åºã-ã»ãšãã©ã®å Žåãåçã«ããŒããããŸããããã以å€ã®å Žåã¯ããã€ããªãã¡ã€ã«ã®IATïŒã¢ãã¬ã¹ã€ã³ããŒãããŒãã«ïŒããã¢ã¯ã»ã¹ããããããããã«å¿ããŠåŠçããå¿ èŠããããŸãã
â¢ã°ããŒãã«å€æ°ããã€ãã£ãã³ãŒã-äžéšã®ã°ããŒãã«å€æ°ã¯ãä»®æ³åããããã€ããªã«ä¿åããå¿ èŠããããŸãããŸããFinFisherãããããŒã«ã¯ãx64ãšx86ãåãæ¿ããæ©èœããããããã¯ããã»ããµãŒã¢ãŒãã§å®è¡ãããŸãïŒå®éãããã¯ã³ãã³ãã§ã®ã¿è¡ãã
retf
ãŸãïŒããããã¯ãã¹ãŠãã³ã³ãã€ã«äžã«ä¿æããå¿ èŠããããŸãã
çµæã«ãã£ãŠã¯ãéã¢ã»ã³ãã©ã®åºåã§ãã³ã³ãã€ã«å¯èœãªçŽç²ã«ç¬èªã®ã³ãã³ããååŸããããã«ãããã«ããã€ãã®å€æŽãè¡ãå¿ èŠãããå ŽåããããŸãã次ã«ã奜ã¿ã®ã³ã³ãã€ã©ã䜿çšããŠãä»®æ³ãã·ã³ãªãã§ãã€ããªã«ã³ãŒããã³ã³ãã€ã«ããå¿ èŠããããŸãã
ãããã«
ãã®ã¬ã€ãã§ã¯ãFinFisherã2ã€ã®æ¹æ³ã䜿çšããŠäž»èŠãªææç©ãä¿è·ããæ¹æ³ã«ã€ããŠèª¬æããŸãããä¿è·ã®ç®çã¯ããŠã€ã«ã¹å¯Ÿçã®æ€åºã«å¯Ÿæããããšã§ã¯ãªãããªããŒã¹ãšã³ãžãã¢ãªã³ã°ã®åé¡ãäœæããããšã«ãããã¹ãã€ãŠã§ã¢ã§äœ¿çšãããæ§æãã¡ã€ã«ãšæ°ããææ³ãé ãããšã§ããé£èªåãããã¹ãã€ãŠã§ã¢FinFisherã®ä»ã®è©³çŽ°ãªåæã¯ãããŸã§å ¬éãããŠããªãããããããŸã§ãã®ä¿è·ã¡ã«ããºã ã®éçºè ã®ã¿ã¹ã¯ã¯æ£åžžã«å®äºãããšèŠãªãããšãã§ããŸããã
å解ã«å¯Ÿããä¿è·ã¬ãã«ãèªååãããæ¹æ³ã«ãã£ãŠã©ã®ããã«å æã§ããããä»®æ³ãã·ã³ãå¹æçã«åæããæ¹æ³ã瀺ããŸããã
ãã®ã¬ã€ãããFinFisherã§ä¿è·ãããä»®æ³ãã·ã³ã®ãµã³ãã«ãåæãããªããŒã¹ãšã³ãžãã¢ãªã³ã°ã®å°é家ãå©ããä»®æ³ãã·ã³å šäœã䜿çšããä¿è·ã®è©³çŽ°ãããããç解ããããšãé¡ã£ãŠããŸãã
ä»é²A
FinFisherã§vm_handlersãã³ãã©ãŒã«ååãä»ããããã®Python IDAã¹ã¯ãªãã
ãã®ã¹ã¯ãªããã¯ãGitHubã®ESETãªããžããªã§ãå©çšã§ããŸãã
import sys SIGS={'8d4b408b432c8b0a90800f95c2a980000f95c03ac275ff631c':'case_0_JL _loc1','8d4b408b432c8b0a9400074ff631c':'case_1_JNP_loc1','8d4b408b432c 8b0a94000075a90800f95c2a980000f95c03ac275ff631c':'case_2_JLE_loc1','8d4 b408b7b508b432c83e02f8dbc38311812b5c787cfe7ed4ae92f8b066c787d3e7e 4af9b8e80000588d80' : 'case_3_vm_jcc', '8b7b508b432c83e02f3f85766c77ac6668 137316783c728d7340fb64b3df3a4c67e98037818b43c89471c64756c80775af83318588b6 32c' : 'case_4_exec_native_code', '8d4b408b98b438898833188b43c8b632c' : 'c ase_5_mov_tmp_REGref_arg0', '8b7b508b432c83e02f3f85766c77ac6668137316783c7 28d7340fb64b3df3a4c67e98037818b43c89471c64756c80775af83318588b632c' : 'cas e_6_exec_native_code','8d4b408b432c8b0a94000075ff631c':'case_7_JZ_loc1' , '8d4b408b432c8b0a94000075a90800f95c2a980000f95c03ac275ff6318' : 'case_8_ JG_loc1','8d43408b089438833188b43c8b632c':'case_9_mov_tmp_REG_arg0','3 3c9894b8833188b632c8b43c' : 'case_A_zero_tmp_REG', '8d4b408b432c8b0a980000 75ff631c':'case_B_JS_loc1','8d4b40fb69b870002bc18b4b2c8b548148b4b889118 33188b43c8b632c' : 'case_C_mov_tmp_REGDeref_tmp_REG', '8d4b40fb69b870002bc 18b4b2c8b4481489438833188b43c8b632c' : 'case_D_mov_tmp_REG_tmp_REG', '8d4b 408b432c8b0a9100075ff631c':'case_E_JB_loc1','8d4b408b432c8b0a9100075a94 000075ff631c':'case_F_JBE_loc1','8d4b408b432c8b0a94000074ff631c':'cas e_10_JNZ_loc1','8d4b408b432c8b0a9080074ff631c':'case_11_JNO_loc1','8b7 b50834350308d4b408b414343285766c773f50668137a231c6472c280772aa8d57d83c7389 1783ef3c7477a300080777cb83c7889783ef8c647cf28077c3183c7dc67688b383c0188947 183c7566c7777fe668137176283c72c672d803745895f183c75c67848037df478b4314c674 08037288947183c75c67928037515f8b632c' : 'case_12_vm_call', '8d4b40b870002b 18b532c8b4482489438833188b43c8b632c' : 'case_13_mov_tmp_REG_tmp_REG_notRly ','8d4b408b432c8b0a9400075ff631c':'case_14_JP_loc1','8d4b40fb69b870002 bc18b4b2c8b5388954814833188b43c8b632c' : 'case_15_mov_tmp_REG_tmp_REG', '8 d4b408b432c8b0a9080075ff631c':'case_16_JO_loc1','8d4b408b432c8b0a90800f 95c2a980000f95c03ac274ff631c':'case_17_JGE_loc1','8b4388b089438833188b4 3c8b632c' : 'case_18_deref_tmp_REG', '8d4b408b4388b9d3e089438833188b43c8b6 32c' : 'case_19_shl_tmp_REG_arg0l', '8d4b408b432c8b0a98000074ff631c' : 'ca se_1A_JNS_loc1','8d4b408b432c8b0a9100074ff631c':'case_1B_JNB_loc1','8b 7b2c8b732c83ef4b924000fcf3a4836b2c48b4b2c8b438894124833188b43c8b632c' : 'c ase_1C_push_tmp_REG', '8d4b408b432c8b0a94000075a9100075ff6318' : 'case_1D_ JA_loc1','8d4b40b870002b18b532c8b448241438833188b43c8b632c':'case_1E_ad d_stack_val_to_tmp_REG', '8b7b508343503066c77ac3766813731565783c728d4b40c6 72e803746fb6433d3c783c058947183c758d714fb64b3df3a45ac671280377a8b383c01889 47183c7566c777f306681371fac83c72c671f803777895f183c75c677080372b47c6798037 618b4b14894f183c75c67778037b48b632c8d12' : 'case_1F_vm_jmp', '8d4b408b914b 8833188b43c8b632c' : 'case_20_add_arg0_to_tmp_REG', '8d4b408b98b4388918331 88b632c8b43c' : 'case_21_mov_tmp_REG_to_arg0Dereferenced' } SWITCH = 0 # addr of jmp dword ptr [eax+ecx*4] (jump to vm_handlers) SWITCH_SIZE=34 sig = [] def append_bytes(instr, addr): for j in range(instr.size): sig.append(Byte(addr)) addr += 1 return addr defmakeSigName(sig_name,vm_handler): print ânaming %x as %sâ % (vm_handler, sig_name) MakeName(vm_handler,sig_name) return if SWITCH == 0: print âFirst specify address of switch jump - jump to vm_handlers!â sys.exit(1) foriinrange(SWITCH_SIZE): addr = Dword(SWITCH+i*4) faddr = addr sig = [] while 1: instr = DecodeInstruction(addr) if instr.get_canon_mnem() == âjmpâ and (Byte(addr) == 0xeb or Byte (addr) == 0xe9): addr = instr.Op1.addr continue if instr.get_canon_mnem() == âjmpâ and Byte(addr) == 0xff and Byte (addr+1) == 0x63 and (Byte(addr+2) == 0x18 or Byte(addr+2) == 0x1C): addr = append_bytes(instr, addr) break if instr.get_canon_mnem() == âjmpâ and Byte(addr) == 0xff: break if instr.get_canon_mnem() == âjzâ: sig.append(Byte(addr)) addr += instr.size continue if instr.get_canon_mnem() == âjnzâ: sig.append(Byte(addr)) addr += instr.size continue if instr.get_canon_mnem() == ânopâ: addr += 1 continue addr = append_bytes(instr, addr) sig_str = ââ.join([hex(l)[2:] for l in sig]) hsig = ''.join(map(chr, sig)).encode(âhexâ) for key, value in SIGS.iteritems(): if len(key) > len(sig_str): ifkey.find(sig_str)>=0: makeSigName(value,faddr) else: ifsig_str.find(key)>=0: makeSigName(value,faddr)