Hello guys, today I'm going to demonstrate how to use Labeless to obtain API names.
The malware often use not trivial methods to call some API. In our case there is some function which receives hashes of dll and procedure name and returns API address and then calls it...
So, the easiest way to get result is to trace all references in debugger
There are some tools which we can use:
- OllyDbg 1.10
- OllyDbg 2.01
- x64dbg x32
- x64dbg x64
Unforunatelly, OllyDbg 1.10 have no easy way to trace/manage debuggee as we want.
The OllyDbg 2.01 and x64dbg (x32, x64) are useful for us.
So, for this case I choose OllyDbg 2.01
...
.text:00401437 push 16A7B107h
.text:0040143C push 0D8DF5355h
.text:00401441 call fmfu_GetProcAddr
The call to our function looks like sequence of push
+ push
+ call
There are 14 references to this function 0x00401190
Our task is to prepare groups of addresses, which should be traced IDA PRO has useful API for us:
CodeRefsTo(ea, flow)
- get a list of refsFuncItems(start)
- get a list of function items (instructions)
Let's collect needed addresses first...
Before doing anything, we should check the connectivity with the debugger in the settings view (by pressing Test connection
)
Ok, connected successfully, then we should check the remote module base (base address, where the target module (exe, dll) is mapped)
0x00F00000
- the remote base, it's different with the IDA's base (0x400000
). We should put this base in the settings view...
There are some functions, named by IDA using signatures, let's propagate names (Labels) to the debugger Cool :)
In the main()
function there are few calls to LoadLibrary
. let's trace to initialize... Ok
Ok, now we have trace points, but we need to convert local base to remote one...
Ok, we should transfer the trace points to debugger, the __extern__
variable will help us do this.
__extern__
will be a list of dictionaries with one field eas
Ok, we may see the addresses in the output from debuggee
The next step is to trace over all trace points and for each try to resolve API name from EAX register after each call
The OllyDbg 2.01 API has few useful functions:
SetEip()
inthreads
moduleStepOver()
inutils
moduleFindnameW(ulong addr, int type, wchar_t * name, int nname) -> int
(in theapi
module)Findmodule(ulong addr) -> t_module
(in theapi
module)GetEax()
in threads module
Cool, we have traced over all trace points and got the APIs
Now, we should transfer them back to the IDA using __result__
variable
and then propagate the names of APIs as comments...
Let's try to add the module name of API before to be like 'kernel32.OpenProcess' Ok
set_cmt
API will help us to set comment
set_cmt(ea, comm, rptble)
One more thing to do - convert remote EA to local
we have unicode string name, need to convert it to ansi Ok, that's better
# let's prepare trace points...
from idautils import CodeRefsTo, FuncItems
fn_ea = 0x00401190
base = 0x400000
remote = 0x00F00000
refs = list(CodeRefsTo(fn_ea, 0))
print 'found %d refs' % len(refs)
__extern__ = list()
for ref in refs:
items = list(FuncItems(ref))
# there we have all EAs (addresses) of function where ref is
# use only tree of them (ea of push, ea of push, ea of call)
idx = items.index(ref)
EAs = items[idx - 2: idx + 1]
EAs = [remote + (ea - base) for ea in EAs]
# for example ea = 0x401324
# the remote ea = F00000 + (401324 - 400000)
# print [hex(int(ea)) for ea in EAs]
__extern__.append({'eas': EAs})
# --- olly2
import ctypes as C
buff = C.create_unicode_buffer(ll.api.TEXTLEN)
__result__ = list()
for item in __extern__:
EAs = item['eas']
for ea in EAs:
ll.threads.SetEip(ea)
ll.utils.StepOver()
# at this point we have the context after 'call' insn
eax = ll.threads.GetEax()
# now we should try to resolve the name of API in EAX
if ll.api.FindnameW(eax, ll.api.NM_EXPORT, buff, ll.api.TEXTLEN) > 0:
name = buff.value.replace('\0', '')
module = ll.api.Findmodule(eax)
if module:
name = '%s.%s' % (module.modname.replace('\0', '').lower(), name)
print 'eax: %#08x %s' % (eax, name)
__result__.append({'ea': EAs[-1], 'name': name})
else:
print '[-] unable to get name for %#08x' % eax
__result__.append({'ea': EAs[-1], 'name': None})