Decoders again


Author: David Zimmer
Date: 08.27.16 - 2:50am



Turns out I have allot to say on the topic of writing off hand decoders. We have discussed using an array of bytes black box as char buffers, loading entire exes/dlls in memory, running byte blobs in scdbg for emulation, patching function offsets into blobs, directly using the disasm from IDA in Visual Studio, turning a virus into your own private IPC decoder service etc.

Today I will cover another quick and dirty technique using _emit

So I had a decoder to rip from a malware today. First I tried the hexrays decompilation output as C, VS complained. Ok, then I switched over to using an exported asm dump of the function and _asm. VS complained. Some fidgeting is expected, but I was in a rush and just didnt have time to play with it.

If it was a standalone function I would just call it directly from a function pointer to a byte buffer, but there was one relative call to a compiled in version of memcpy
E8 CB 06 00 00   call    _memcpy
I could expand the buffer and include my own asm opcodes for
B8 B31D907C    MOV EAX, memcpy
FFD0           CALL EAX
this gives me the hardcoded offset I can latter patch at runtime with the actual address of memcpy (here 0x7C901DB3), but again, time is limited and I just didnt feel like the hassle.

what I wanted was a way to just declare a C function, have it spit out all the bytes I wanted, and somewhere in the blob I could just add my inline asm call memcpy. Thats easier and quicker than making my own asm call and patching in the address at runtime right?

Ok, so how do you do this? Welcome to the world of _asm _emit

int __declspec(naked) decoder(char* buf, int sz, unsigned int key)
{
 	_asm _emit 0x55 _asm _emit 0x8B ...
        ...
	_asm call memcpy
        ...
	_asm _emit 0xC3
}


Pretty easy. Now you dont have to fight with the compiler at all. Your still running it as a black box, and function calls will always link right. Downside, you have to debug it in olly and you dont really want to have to change bytes this way, but if you are ripping functions like this, its already a known working thing. Just make sure your prototypes and arguments are correct.

So now, we need an easy way to generate the emit buffers. For this I made a couple small idajs scripts. The first one just dumps a compact emit blob of the byte codes. The second one dumps the disasm and the opcodes on individual lines for easy editing.

Enjoy.

//emit_cur_func.idajs
ea = ida.screenEA()
funcIndex = ida.funcIndexFromVA(ea)
if(funcIndex == -1) throw("Cursor not in a function: ea="+h(ea)+" i="+funcIndex);

fName = ida.functionName(funcIndex);
fStart = ida.functionStart(funcIndex);
fEnd = ida.functionEnd(funcIndex);

tmp = '';j=0;x = new Array();
x.push("// opcodes for " + fName + " size: 0x" + h(fEnd-fStart) + " bytes
");

for(i = fStart; i < fEnd; i++){
    tmp+= "_asm _emit 0x" + h(ida.readByte(i)) + " ";
    j++;
    if(j == 6){
        x.push('	'+tmp);
        tmp = '';
        j=0;
    }
}

if(tmp.length > 0) x.push('	'+tmp);
x.push(' }');
x = x.join('
')
app.setClipboard(x)
t(x)




//emit_with_disasm.idajs
ea = ida.screenEA()
funcIndex = ida.funcIndexFromVA(ea)
if(funcIndex == -1) throw("Cursor not in a function: ea="+h(ea)+" i="+funcIndex);

fName = ida.functionName(funcIndex);
fStart = ida.functionStart(funcIndex);
fEnd = ida.functionEnd(funcIndex);

tmp = '';x = new Array();
x.push("// opcodes for " + fName + " size: 0x" + h(fEnd-fStart) + " bytes");

i = parseInt(fStart); //duk takes i as string if not weird..
while(i < fEnd){  
    sz = ida.instSize(i);
    if(sz < 1){
        alert("Inst size 0 @ "+h(i));
        break;
    }
    for(j = 0; j < sz; j++){    
        tmp+= "_asm _emit 0x" + h(ida.readByte(i+j)) + " ";
    }
    tmp = padAsm(i) + tmp;
    
    i+=sz;
    x.push('	'+tmp);
    tmp = ''
}

x = x.join('
')
app.setClipboard(x)
t(x)

function padAsm(va){
   defLen = 45;
   asm = ida.getAsm(va);
   a = asm.indexOf(';'); //ida strip comments
   if(a > 0) asm = asm.substring(0,a);
   while(asm.length < 30) asm+=' ';
   asm = "/* " + asm + " */  "
   return asm;
}




Example output:

1)
// opcodes for decoder size: 0xD3 bytes
 	_asm _emit 0x55 _asm _emit 0x8B _asm _emit 0xEC _asm _emit 0x83 _asm _emit 0xEC _asm _emit 0x0C 
	_asm _emit 0x6A _asm _emit 0x04 _asm _emit 0x8D _asm _emit 0x45 _asm _emit 0x10 _asm _emit 0x50 

2)
// opcodes for decoder size: 0xD3 bytes
	/* push    ebp                    */  _asm _emit 0x55 
	/* mov     ebp, esp               */  _asm _emit 0x8B _asm _emit 0xEC 
	/* sub     esp, 0Ch               */  _asm _emit 0x83 _asm _emit 0xEC _asm _emit 0x0C 





Comments: (1)

On 08.27.16 - 7:50am Dave wrote:
the second script is actually a really convenient way to edit the code, you dont have to worry about the details of the byte blob and making VS happy with its disasm syntax, and you can still edit exactly the portions you want inline without trying to insert code using copymemory calls

 
Leave Comment:
Name:
Email: (not shown)
Message: (Required)
Math Question: 71 + 72 = ? followed by the letter: I 



About Me
More Blogs
Main Site
Posts: (year)
2023 (4)
     Yara Workbench Automation
     VS linker versions
     IDA decompiler comments
     DispCallFunc
2022 (5)
     VB6 Implements
     VB6 Stubs BS
     VB6 TypeInfo
     VB6 VTable Layout
     Yara isPCode rule
2021 (2)
     rtcTypeName
     VB6 Gosub
2020 (5)
     AutoIT versions
     IDA JScript 2
     Using VB6 Obj files from C
     Yara Corrupt Imports
     Yara Undefined values
2019 (6)
     Yara WorkBench
     SafeArrayGetVartype
     vb6 API and call backs
     PrintFile
     ImpAdCallNonVirt
     UConnect Disable Cell Modem
2017 (5)
     IDA python over IPC
     dns wildcard blocking
     64bit IDA Plugins
     anterior lines
     misc news/updates
2016 (4)
     KANAL Mod
     Decoders again
     CDO.Message Breakpoints
     SysAnalyzer Updates
2015 (5)
     SysAnalyzer and Site Updates
     crazy decoder
     ida js w/dbg
     flash patching #2
     JS Graphing
2014 (5)
     Delphi IDA Plugin
     scdbg IDA integration
     API Hash Database
     Winmerge plugin
     IDACompare Updates
2013 (9)
     Guest Post @ hexblog
     TCP Stream Reassembly
     SysAnalyzer Updates
     Apilogger Video
     Shellcode2Exe trainer
     scdbg updates
     IDA Javascript w/IDE
     Rop Analysis II
     scdbg vrs ROP
2012 (13)
     flash patching
     x64 Hooks
     micro hook
     jmp api+5 *2
     SysAnalyzer Updates
     InjDll runtime config
     C# Asm/Dsm Library
     Shellcode Hook Detection
     Updates II
     findDll
     Java Hacking
     Windows 8
     Win7 x64
2011 (19)
     Graphing ideas
     .Net Hacking
     Old iDefense Releases
     BootLoaders
     hll shellcode
     ActionScript Tips
     -patch fu
     scdbg ordinal lookup
     scdbg -api mode
     Peb Module Lists
     scdbg vrs Process Injection
     GetProcAddress Scanner
     scdbg fopen mode
     scdbg findsc mode
     scdbg MemMonitor
     demo shellcodes
     scdbg download
     api hashs redux
     Api hash gen
2010 (11)
     Retro XSS Chat Codes
     Exe as DLL
     Olly Plugins
     Debugging Explorer
     Attach to hidden process
     JS Refactoring
     Asm and Shellcode in CSharp
     Fancy Return Address
     PDF Stream Dumper
     Malcode Call API by Hash
     WinDbg Cheat Sheet
2009 (1)
     GPG Automation