Decoders againAuthor: 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 _memcpyI could expand the buffer and include my own asm opcodes for B8 B31D907C MOV EAX, memcpy FFD0 CALL EAXthis 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:
|
About Me More Blogs Main Site |
|