PDA

View Full Version : My First Script: Stack based generic a s p r u n p


orion
June 30th, 2004, 20:11
//////////////////////////////////////////////////////////////////////
// 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

orion
June 30th, 2004, 20:19
tested on a s p r 1.2x. Also tested with 1.3 with very good result.
EDIT: No target names plz! /psyCK0

A few notes:

There is no reference to specific code positions in this script. It uses stack pattern which I think it is less frequently changed.

packers can not mess with system dll's code but we can

If packer allocate a new block of memory and run code there, we can use it to our advantage (GMI comes handy)

orion
June 30th, 2004, 20:20
as you can see, I used a s p r with space to fool search engines.

orion
June 30th, 2004, 20:33
To make dll fully relocatable, don't forget to correct reloc table address in pe header, lucky a s p r keeps reloc table intact so it is a easy job.

psyCK0
July 1st, 2004, 02:35
Nice one... Do you want me to put it on the OSC site?

orion
July 1st, 2004, 07:22
Yes, so more people can test it with different versions to see how generic it really is. The script will change quite frequently though as I intend to improve/fix it often.

orion
July 1st, 2004, 13:47
How embarrassing, I was wrong when I say it works on one point three. The script worked on c32asm.dll, not c32asm.exe. The two file are protected by different schemes.

Anonymous
July 4th, 2004, 09:13
Maybe it sounds stupid, but it's enough to copy & paste some plugin to txt file to work properly? Coz when I check psyCKO page, all plugins are in HEX? format not plain text. How do you psyCKO save plugin here posted to file ? Thx for explanation.

psyCK0
July 4th, 2004, 09:44
All scripts are in plain text format on my site.

shERis
July 5th, 2004, 15:16
Hi orion!
I tested your script on d z p h p e d . e x e (from download ("http://www.dzsoft.com/download/dzphp20.exe")).
This proggy is packed with an a s p r -version.
But your script does´nt work. It causes the error "Stack search failed".
Is a newer version of a s p r used ?
The api calls are indirect and direct in a s p r code!

psyCK0
July 5th, 2004, 16:49
orion: Added your script to my site =)