Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. /* RunPE unpacker - interestingmalware@gmail.com
  2.  *
  3.  * Based on the example at http://www.hex-rays.com/idapro/scriptable.htm
  4.  */
  5.  
  6. #include <idc.idc>
  7.  
  8. // flag for CreateProcess()
  9. #define CREATE_SUSPENDED 0x4
  10.  
  11. static main() {
  12.   auto code, bptea;
  13.   auto esp, flags;
  14.   auto buffer;
  15.   auto filename = "unpacked.exe";
  16.  
  17.   // ignore EXCEPTION_FLT_INEXACT_RESULT. VB6 uses this a lot and usually
  18.   // handles the exception, but it makes things a pain for debuggers
  19.   SetExceptionFlags(0xC000008F, 0);
  20.  
  21.   Message("Starting process...\n");
  22.  
  23.   // launch the debugger and run until the entry point
  24.   if (!RunTo(BeginEA()))
  25.     return Warning("Can't debug to entrypoint");
  26.  
  27.   // wait until process is suspended
  28.   code = GetDebuggerEvent(WFNE_SUSP, -1);
  29.   if (code <= 0)
  30.     return Warning("Can't get debugger event");
  31.  
  32.   // set breakpoint on CreateProcessW
  33.   bptea = AddHardwareBp("kernel32_CreateProcessW");
  34.   if(!bptea)
  35.     return Warning("Can't break on CreateProcessW");
  36.  
  37.   // resume the execution and wait until CreateProcessW is called
  38.   code = GetDebuggerEvent(WFNE_SUSP|WFNE_CONT, -1);
  39.   if (code <= 0)
  40.     return Warning("Can't resume execution for CreateProcessW breakpoint");
  41.  
  42.   DelBpt(bptea);
  43.  
  44.   // check arguments to CreateProcessW    
  45.   esp = GetRegValue("ESP");
  46.   Message("CreateProcessW called from %.8X\n", Dword(esp));
  47.   Message("  lpApplicationName: %s\n", GetString(Dword(esp+4), -1, ASCSTR_UNICODE));
  48.   Message("  lpCommandLine: %s\n", GetString(Dword(esp+8), -1, ASCSTR_UNICODE));
  49.  
  50.   // make sure flags contain CREATE_SUSPENDED
  51.   flags = Dword(esp+24);
  52.   if(!(flags & CREATE_SUSPENDED)) {
  53.     return Warning("Process created without CREATE_SUSPENDED flag (flag = %.8X)", flags);
  54.   }
  55.  
  56.   // let the call to CreateProcessW finish - run until the return address is hit
  57.   RunTo(Dword(esp));
  58.   while(1) {
  59.     code = GetDebuggerEvent(WFNE_SUSP|WFNE_CONT, -1);
  60.     if (code <= 0)
  61.         return Warning("Failed to let CreateProcessW finish");
  62.        
  63.     if(code != STEP) break;
  64.    }
  65.  
  66.   // now break on calls to NtWriteVirtualMemory
  67.   bptea = AddHardwareBp("ntdll_NtWriteVirtualMemory");
  68.   if(!bptea)
  69.     return Warning("Can't set breakpoint on NtWriteVirtualMemory");
  70.  
  71.   // resume the execution and wait until NtWriteVirtualMemory is called
  72.   code = GetDebuggerEvent(WFNE_SUSP|WFNE_CONT, -1);
  73.   if (code <= 0)
  74.     return Warning("Can't resume execution for NtWriteVirtualMemory breakpoint");
  75.  
  76.   esp = GetRegValue("ESP");
  77.   buffer = Dword(esp+12);
  78.  
  79.   DelBpt(bptea);
  80.  
  81.   Message("NtWriteVirtualMemory called from %.8X, buffer address: %.8X\n", Dword(esp), buffer);
  82.   Message("Dumping file...\n");
  83.   DumpPE(buffer, filename);  
  84. }
  85.  
  86. // add a hardware breakpoint at the specified name.
  87. // success: returns the address of the breakpoint
  88. // fail: returns 0
  89. static AddHardwareBp(name) {
  90.   auto bptea;
  91.  
  92.   // get address of function
  93.   bptea = LocByName(name);
  94.   if (bptea == BADADDR) {
  95.     Message ("Could not locate %s\n", name);
  96.     return 0;
  97.   }
  98.  
  99.   // set a hardware breakpoint
  100.   Message("Setting a hardware breakpoint on %s\n", name);
  101.  
  102.   // XXX - this should check return value, but sometimes this call fails
  103.   // even when the breakpoint is still set (in IDA 5.7)
  104.   AddBptEx(bptea, 1, BPT_EXEC);
  105.  
  106.   //if(!AddBptEx(bptea, 1, BPT_EXEC)) {
  107.   //  Message("Failed to add hardware breakpoint for %s\n", name);
  108.   //  return 0;
  109.   //}
  110.  
  111.   return bptea;
  112. }
  113.  
  114. // for dump_pe()
  115. #define OPTHEADER_OFFSET 0x18
  116. #define SECTION_HEADER_SIZE 0x28
  117.  
  118. // write a PE file stored in memory to disk. this function determines the size
  119. // of the PE file by calculating the offset of the end of the last section.
  120. // this can miss data stored by some PE files. there are probably better ways
  121. // to do this, but it works for me.
  122. static DumpPE(start_addr, filename) {
  123.   auto nt_headers, num_secs, last_sec;
  124.   auto end_addr;
  125.   auto f, ptr;
  126.  
  127.   // check the DOS header magic value
  128.   SetType(start_addr, "IMAGE_DOS_HEADER;");
  129.   if(Word(start_addr.e_magic) != 0x5a4d) {
  130.     Message("Not an EXE, invalid magic: %x\n", Word(start_addr.e_magic));
  131.     return 0;
  132.   }
  133.  
  134.   nt_headers = start_addr + Dword(start_addr.e_lfanew);
  135.   SetType(nt_headers, "IMAGE_NT_HEADERS;");
  136.  
  137.   // check NT headers magic value
  138.   if(Dword(nt_headers.Signature) != 0x4550) {
  139.     Message("Not a PE, invalid signature: %x\n", Dword(nt_headers.Signature));
  140.     return 0;
  141.   }
  142.  
  143.   // figure out number of sections
  144.   num_secs = Word(nt_headers.FileHeader.NumberOfSections);
  145.   if(num_secs > 16) {
  146.     Message("Sanity check failed, %i sections\n", num_secs);
  147.     return;
  148.   }
  149.  
  150.   // get offset of last section header
  151.   last_sec = nt_headers + OPTHEADER_OFFSET + Word(nt_headers.FileHeader.SizeOfOptionalHeader) +
  152.     (SECTION_HEADER_SIZE * (num_secs - 1));
  153.  
  154.   // figure out offset the end of the last section
  155.   SetType(last_sec, "IMAGE_SECTION_HEADER;");
  156.   end_addr = start_addr + Dword(last_sec.PointerToRawData) + Dword(last_sec.SizeOfRawData);
  157.  
  158.   // sanity check
  159.   if(start_addr == end_addr) {
  160.     Message("Something broke, start = end = %x\n", start_addr);
  161.     return 0;
  162.   }
  163.  
  164.   Message("Writing %i bytes to %s...\n", end_addr - start_addr, filename);
  165.  
  166.   // write the file
  167.   f = fopen(filename, "wb");
  168.   for(ptr=start_addr; ptr<end_addr; ptr++) {
  169.     fputc(Byte(ptr), f);
  170.   }
  171.   fclose(f);
  172.  
  173.   Message("Done writing file\n");
  174.  
  175.   return 1;
  176. }