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: 92 + 7 = ? followed by the letter: F 



About Me
More Blogs
Main Site
Posts: (All)
2023 ( 4 )
2022 ( 5 )
2021 ( 2 )
2020 ( 5 )
2019 ( 6 )
2017 ( 5 )
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 )
2012 ( 13 )
2011 ( 19 )
2010 ( 11 )
2009 ( 1 )