View Single Post
  #1  
Old 07-22-2026, 14:47
Carina0206 Carina0206 is offline
Friend
 
Join Date: Jun 2026
Location: Mars.
Posts: 22
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 1
Thanks Rcvd at 68 Times in 20 Posts
Carina0206 Reputation: 0
IDA script to fix IAT virtualized/obfuscated by Winlicense/Themida

The each element of IAT obfuscated/virtualized by Themida/Winlicense points to some address of vm code section in run-time.

In older versions of Themida/Winlicense, after goes ahead all arbitrary jmp instructions in this vm code section's context jumped from virtualized IAT, when once ret instruction is executed, the current element value of stack is just final API address.

But in newer versions, it is used more complex context which has only arbitrary jmp instructions but also arbitrary call/ret instructions pairs in virtualized code flow.

That is, after goes ahead all arbitrary jmp instructions and call/ret pairs in this vm code section's context jumped from virtualized IAT, when final un-paired ret instruction is executed, the current element value of stack points to right Win32 API address.

These IDA scripts replace all addresses jumped to vm code section with real Win32 API addresses in IAT virtualized/obfuscated by Themida/Winlicense.

In case of x64 executables :
Code:
// This IDA script fixes virtualized/obfuscated IAT of x64 executable files packed by Winlicense/Themida
auto dest_addr, api_addr, temp;
auto iat_begin, iat_end;
auto vm_begin, vm_end;
auto fp, ret_event;
auto is_exception;

vm_begin =   0x0;  // write starting address of your executable's vm section in here
vm_end =     0x0;  // write ending address of your executable's vm section in here
iat_begin =  0x0;  // write starting address of your executable's IAT in here
iat_end =    0x0;  // write ending address of your executable's IAT in here

fp = fopen("D:\\Your-exe-IAT-fix.log", "w");     // replace your log file name in here

for(dest_addr = iat_begin; dest_addr < iat_end; dest_addr = dest_addr + 8)
{
  temp = get_qword(dest_addr);
  if(temp >= vm_begin && temp < vm_end)
  {
     msg("%x  :  %x  :  ", dest_addr, temp);
     fprintf(fp, "%x  :  %x  :  ", dest_addr, temp);
     jumpto(temp);
     refresh_idaview_anyway();
     rip = temp;
     api_addr = temp;

     while((rip >= vm_begin && rip < vm_end))
     {
        step_until_ret();
        wait_for_next_event(WFNE_SUSP, -1);
        if(ret_event == EXCEPTION)
        {
           is_exception = 1;
           break;
        }
     }
 
     if(is_exception == 1)
       break;
 
     api_addr = rip;
     patch_qword(dest_addr, api_addr);

     msg("fixed  :  %x  :  %s\n", api_addr, get_name(api_addr));
     fprintf(fp, "fixed  :  %x  :  %s\n", api_addr, get_name(api_addr));
  }
}

fclose(fp);

msg("Done.\n");
In case of x86 executables :
Code:
// This IDA script fixes virtualized/obfuscated IAT of x86 executable files packed by Winlicense/Themida
auto dest_addr, api_addr, temp;
auto iat_begin, iat_end;
auto vm_begin, vm_end;
auto fp, ret_event;
auto is_exception;

vm_begin =   0x0;  // write starting address of your executable's vm section in here
vm_end =     0x0;  // write ending address of your executable's vm section in here
iat_begin =  0x0;  // write starting address of your executable's IAT in here
iat_end =    0x0;  // write ending address of your executable's IAT in here

fp = fopen("D:\\Your-exe-IAT-fix.log", "w");     // replace your log file name in here

for(dest_addr = iat_begin; dest_addr < iat_end; dest_addr = dest_addr + 4)
{
  temp = get_dword(dest_addr);
  if(temp >= vm_begin && temp < vm_end)
  {
     msg("%x  :  %x  :  ", dest_addr, temp);
     fprintf(fp, "%x  :  %x  :  ", dest_addr, temp);
     jumpto(temp);
     refresh_idaview_anyway();
     eip = temp;
     api_addr = temp;

     while((eip >= vm_begin && eip < vm_end))
     {
        step_until_ret();
        wait_for_next_event(WFNE_SUSP, -1);
        if(ret_event == EXCEPTION)
        {
            is_exception = 1;
            break;
        }
     }
 
     if(is_exception == 1)
        break;
 
     api_addr = eip;
     patch_dword(dest_addr, api_addr);

     msg("fixed  :  %x  :  %s\n", api_addr, get_name(api_addr));
     fprintf(fp, "fixed  :  %x  :  %s\n", api_addr, get_name(api_addr));
  }
}

fclose(fp);

msg("Done.\n");

Usage :

1. Execute target process fully.
2. Suspend target process and dump process image.
3. Open dumped image and decide both IAT address range and vm code section range in IDA.
4. Attach IDA local debugger to suspended target process.
5. Suspend all threads of target process except for current thread(for avoiding anti-debugger protection).
6. Load above script in IDA and change beginning/ending addresses of IAT and vm code section and your log file name.
7. Execute IDA script, wait for completion of script running and check log files for correctness.
8. Compete dumping and making new IAT by using Scylla.

Last edited by Carina0206; 07-22-2026 at 15:05.
Reply With Quote
The Following User Says Thank You to Carina0206 For This Useful Post:
kernel (07-22-2026)