////////////////////////////////////////////////////////////////////// 
// 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