////////////////////////////////////////////////////////////////////// // generic (I hope) a s p r oep finder and import recovery // Author: Orion // Email: oriontrooper@yahoo.com // OS : WinXP SP1, OllyDbg 1.10, OllyScript 0.85 // Note: ignore all exception but memory access and invalid op // Usage: // 1. run the script // at first pause, most import entry are recovered, import table // location is shown in log. verify it. // 2. resume // this will decrypt almost all the remaining entry. // 3. if you think there are entries outside of the range shown in log, // enter start and end address in eax & edx, otherwise don't do anything // 4. resume the script. // 5. repeat 3 and 4 if nessesary ////////////////////////////////////////////////////////////////////// / dbh // this the number of exceptions to wait after // import table is fixed. After this memory range // breakpoint is set to find oep. // Adjust it for better performance. // Too large will miss the oep, // Too small will create extra delay when a s p r does // CRC check on code segment (it will still work, but slow) var memdelay mov memdelay, 2 gmi eip, MODULEBASE var mbase mov mbase, $RESULT gmi eip, CODEBASE var cbase mov cbase, $RESULT gmi eip, CODESIZE var csize mov csize, $RESULT var pe mov pe, mbase add pe, 3c mov pe, [pe] add pe, mbase log mbase log cbase log csize log pe var gp gpa "GetProcAddress", "kernel32.dll" mov gp, $RESULT log gp var iat var iat_value var stk var arg var foundCount var first_iat var last_iat var lastBlock var iatCount // dummy initial value that will not change. mov iat, mbase mov iat_value, [iat] mov first_iat, FFFFFFFF mov last_iat, 00000000 var count mov count, 0 // time to set memory range breakpoint var memcount mov memcount, 100 //large value eoe onException run onException: add count, 1 log count cmp count, 1 je lab_gp cmp count, memcount jne loc_1 log "set mem breakpoint" bc gp bprm cbase, csize eob onException esto loc_1: cmp count, memcount jb loc_2 // are we in original program code? GMI eip, MODULEBASE cmp $RESULT, mbase je lab_last esto loc_2: esto // set bp on kernel32.GetProcAddress lab_gp: bp gp eob onGPA esto onGPA: mov memcount, count add memcount, memdelay // saved values from last breakpoint cmp [iat], iat_value je goodBoy //log "nauty! stolen code, will restore" //log iat //log iat_value //log [iat] mov [iat], iat_value goodBoy: var stk mov stk, esp add stk, 8 // arg is pointer to function name or ord number mov arg, [stk] add stk, 20 mov foundCount, 0 findloop: add stk, 4 cmp [stk], arg je foundArg cmp [stk], mbase jne findloop log "stack search failed" ret // find import address table entry using stack pattern // may be more stable then code search. foundArg: add stk, 0c mov stk, [stk] mov iat, [stk] cmp first_iat, iat jb loc_3 mov first_iat, iat loc_3: cmp last_iat, iat ja loc_4 mov last_iat, iat loc_4: rtr // can not write to [iat] now - a s p r will change it later // save it mov iat_value, eax run lab_last: log "got oep" bc gp log first_iat log last_iat cmp [iat], iat_value je last2 log "fix last iat" mov [iat], iat_value last2: bpmc jmp step2 step2: msg "To decode encrypted iat, resume this script" pause // find out what each encryprted entry really points to // by calling them and intercept calls to "GetProcAddress" bp gp var saveeip var breakreturn var saveesp var saveop mov saveeip, eip mov breakreturn, eip add breakreturn, 3 mov saveop, [eip] mov [eip], #60# // pushad sti // save registers dec eip mov [eip], #33c0c390# // xor ax, ax; ret; nop sub esp, 100 mov saveesp, esp log saveop bp breakreturn var repairstart var repairend mov repairstart, first_iat mov repairend, last_iat mov iat, repairstart eob onBreak process_iat: cmp [iat], 0 je nextiat // if iat points to a dll function already, // gmi will return the modulebase of that // library, which is not zero gmi [iat], MODULEBASE cmp $RESULT, 0 // already points to dlls jne nextiat mov eip, [iat] mov esp, saveesp mov [esp], cbase //this is an invlid arg to GetProcAddress sub esp, 4 mov [esp], 0 sub esp, 4 mov [esp], breakreturn // call this iat run nextiat: add iat, 4 cmp iat, repairend ja iatfinish jmp process_iat onBreak: cmp eip, gp je hitGP // returned to breakreturn cmp eax, mbase // if you call GetModuleHandleA with 0, // current modulebase is returned je api_gmh //pause jmp nextiat api_gmh: GPA "GetModuleHandleA", "kernel32.dll" mov [iat], $Result log [iat] jmp nextiat hitGP: rtr cmp eax, 0 // if GetProcAddress fails, and none of the dlls are missing // (make sure your program runs first!). The only possibility is // it is directly called from this script with wrong argument. // which means this iat entry jump to GetProcAddress directly // instead of call it to get a pointer. je api_gpa mov [iat], eax log [iat] // change address to our dummy library function mov eax, saveeip run api_gpa: // GetProcAddress mov [iat], gp run iatfinish: mov eax, 0 msg "Put start address in EAX, End address in EDX to manually decode, or leave it at 0" pause cmp eax, 0 je goodnight mov repairstart, eax mov repairend, edx mov iat, repairstart jmp process_iat goodnight: bc gp bc breakreturn mov esp, saveesp add esp, 100 mov eip, saveeip mov [eip], #61# //popd sti dec eip mov [eip], saveop cmt eip,"!!!!!!!!!!!!!!!!!!" an eip dbs ret