Skip to main content

Reversing a trojan

posted onNovember 19, 2000
by hitbsecnews

This is just a little paper(actually, mostly just notes) about a trojan
that my friend sent me to take a look at, maybe it will help some people
become familiar with softice, or even the concept of a trojan.

The trojan was sent to my friend as 'SRVCP.EXE'
SRVCP EXE 34,336 04-25-01 11:51p srvcp.exe

I first ran the executable with a utility called 'regmon' running, regmon
just detects reads/writes to the registry, you can set it to filter out
certain programs, or even to just log writes or reads, or errors,
successes etc.. really useful. The program access a lot of regkeys mostly
internet settings, but the one we're really interested in is the one it
creates:

23066.20687520 Srvcp SetValueEx
HKLMSOFTWAREMicrosoftWindowsCurrentVersionRunService Profiler
SUCCESS "srvcp.exe"

Be sure to delete this key when removing the trojan.

When I first looked at this trojan I opened it up in WDASM 8.3(A
dissasembler) and I noticed one of the exports is MSCRT.DLL, so to follow
this in softice, you'll have to make sure you enable the export symbols in
your winice.dat and reboot. This will enable us to set breakpoints on the
common C functions.

Still looking at the dissasembly listing in W32DASM I noticed a few interesting strings, and pieces of code I will later set breakpoints on:

* Possible StringData Ref from Data Obj -> "nhl*pwf" // following this is
about 6 more 'garbage strings' seems like // some kind of encryption, all
the strings get pushed onto the stack and then the function located here:
// :004025E2 E8C1420000 call 004068A8 gets called.

Set a breakpoint on this call, the first string which is nhl*pwf is
actually 'gus.ini' which is simple encrypt with a simple XOR scheme.

The following is a list of the encrypted string references along with
their plaintext equivalents:
* Possible StringData Ref from Data Obj -> "piiffmk"

joeblow


* Possible StringData Ref from Data Obj -> "nfplgc"

beotch


* Possible StringData Ref from Data Obj -> "tt`omwg"

funkers

* Possible StringData Ref from Data Obj -> "KmoRlinkJ"

KimmiTheB

* Possible StringData Ref from Data Obj -> "=n$m&n(s*j,e"

d.i.v.i.d.e1

* Possible StringData Ref from Data Obj -> "`HfNK"

JLeLe
* Possible StringData Ref from Data Obj -> "O_ATU@VDE@"
AGGRESSIVE

The encryption routine:

:004068CA FF7508 push [ebp+08] // push encryption 'hash'
onto stack

* Reference To: CRTDLL.strlen, Ord:0272h //
strlen(encrypted_hash) returns 7

|
:004068CD E816040000 Call 00406CE8
:004068D2 83C404 add esp, 00000004
:004068D5 8945F4 mov dword ptr [ebp-0C], eax //
eax=7(return value from strlen)
:004068D8 8B7DF4 mov edi, dword ptr [ebp-0C] // store
it in edi
:004068DB 897DFC mov dword ptr [ebp-04], edi // save it
:004068DE EB40 jmp 00406920 //
unconditional jump ----> 00406920
:004068E0 8B7DFC mov edi, dword ptr [ebp-04] // length
of string into edi
:004068E3 8B5D08 mov ebx, dword ptr [ebp+08] // pointer
to our encrypted hash
:004068E6 8A5C1FFF mov bl, byte ptr [edi+ebx-01] // 7+ptr
to string-01 gives us 'f' the last char
:004068EA 885DFB mov byte ptr [ebp-05], bl // save it
:004068ED 0FBE7DFB movsx edi, byte ptr [ebp-05] // last
byte of hash into edi 'f'
:004068F1 8B75F4 mov esi, dword ptr [ebp-0C] //
7(length) into esi
:004068F4 2B75FC sub esi, dword ptr [ebp-04] // 7-7 esi
= 0
:004068F7 89F0 mov eax, esi // eax = 0
:004068F9 83C001 add eax, 00000001 // eax = 1
:004068FC B91E000000 mov ecx, 0000001E // 31 into
ecx
:00406901 99 cdq // clear
edx
:00406902 F7F9 idiv ecx // ecx
divided by eax, remainer to edx
:00406904 89FB mov ebx, edi //
ebx=0x66
:00406906 31D3 xor ebx, edx // ebx ^ 1
= 0x67 'g'
:00406908 885DFB mov byte ptr [ebp-05], bl // save it
:0040690B 8B7DF4 mov edi, dword ptr [ebp-0C] // edi=7
:0040690E 89FB mov ebx, edi // ebx=7
:00406910 2B5DFC sub ebx, dword ptr [ebp-04] // 7-7=0
:00406913 8A55FB mov dl, byte ptr [ebp-05] // 'f' or
0x66 into dl
:00406916 88941DF4FBFFFF mov byte ptr [ebp+ebx-0000040C], dl //
save dl
:0040691D FF4DFC dec [ebp-04] //
decrease the length, which is our counter
:00406920 837DFC00 cmp dword ptr [ebp-04], 00000000 //
0? nothing left to decrypt
:00406924 7FBA jg 004068E0 //
else jump to 004068E0 and continue decrypt
:00406926 8DBDF4FBFFFF lea edi, dword ptr [ebp+FFFFFBF4] //
load plaintext

So basically:

x = strlen(plain);
for (i=0;i
---

The next thing I did was set out to see how it receives its commands, and
where. Basically, I noticied that it called sprintf() to setup our IRC
ident/nickname/etc, so I set a breakpoint here to grab my nickname, it
happened to be Guest70501. Now If you look at the dissasembly you see
recv() is called numerous places in the code, so set a breakpoint on
recv() and send a message to the client, I just sent 'HELP' it didn't
respond back but of course I broke into softice into this piece of code:

* Reference To: wsock32.recv, Ord:004Fh
|
:004046A4 E8EB230000 Call 00406A94 // recv()
:004046A9 83F800 cmp eax, 00000000 // recv returns the
number of bytes, so 0 is not good
:004046AC 0F8F47E6FFFF jg 00402CF9 // if greater than,
which it will be, jump.

-

:00402CF9 C78570FAFFFF00000000 mov dword ptr [ebp+FFFFFA70], 00000000
// land here, set what ebp+fffffa70 points
// to, to 0
:00402D03 8DBD28F3FFFF lea edi, dword ptr [ebp+FFFFF328]
// load the poiinter to our text into edi
:00402D09 897DF8 mov dword ptr [ebp-08], edi //
mov edi into what ebp-08 points to
:00402D0C E95F190000 jmp 00404670 //
and jump

-
:00404670 837DF800 cmp dword ptr [ebp-08], 00000000 //
check and see if there is text
:00404674 0F8597E6FFFF jne 00402D11 // if
we have text, jump

-
:00402D11 6A0A push 0000000A // push 0xA, which is a
NEWLINE character
:00402D13 FF75F8 push [ebp-08] // pointer to address
which holds our buffer

* Reference To: CRTDLL.strchr, Ord:026Bh

|
:00402D16 E8A93F0000 Call 00406CC4 // call
:00402D1B 83C408 add esp, 00000008 // fix stack
:00402D1E 8945FC mov dword ptr [ebp-04], eax // save
return value
:00402D21 83F800 cmp eax, 00000000 // was it
NULL ? not found.
:00402D24 741D je 00402D43 // if so jump
:00402D26 8B5DFC mov ebx, dword ptr [ebp-04] // move
pointer to return value into ebx
:00402D29 C6041D0000000000 mov byte ptr [ebx+00000000],00 // put 00
into the first location
:00402D31 8B7DFC mov edi, dword ptr [ebp-04] // move
return value into edi
:00402D34 807FFF0B cmp byte ptr [edi-01], 0B // compare
whats at the address pointed to by edi-01
to 0B
:00402D38 7515 jne 00402D4F // if not
equal, jump

-
:00402D4F 8B7DFC mov edi, dword ptr [ebp-04] // move into
edi
:00402D52 89BD6CFAFFFF mov dword ptr [ebp+FFFFFA6C], edi //
save it
:00402D58 8B7DF8 mov edi, dword ptr [ebp-08] // mov
into edi
:00402D5B 803C3D000000003A cmp byte ptr [edi+00000000], 3A //
compare it to 3A which is a colon :
:00402D63 7420 je 00402D85 // if
equal, jump

-
:00402D85 6A02 push 00000002 // push 2 onto
stack
:00402D87 FF75F8 push [ebp-08] // and whats
pointed to by ebp-08
:00402D8A E875310000 call 00405F04 // call

-

Ok, basically I omitted all this code cuz I'm too lazy to comment it, but
what it does is you push a buffer of text and a numerical value onto the
stack as parameters, it then just loops through and breaks up the
buffer(space delimited) and if you push the value 2 it will take the
second 'buffer'. ie: you call it like so:

func(02,"hello world") will return a buffer which contains "world"
func(03,"my name is joe") will return "is" etc..

Now it takes the second buffer because thats what will contain the IRC
command, which happens to be PRIVMSG and then it calls a function to check
what command we called:

:00405A5E 55 push ebp
:00405A5F 89E5 mov ebp, esp
:00405A61 57 push edi
:00405A62 6A03 push 00000003 // size of 'NIC'
command its actually NICK, but shotened

* Possible StringData Ref from Data Obj -> "NIC"

|
:00405A64 6885A44000 push 0040A485 // NIC stored here
:00405A69 FF7508 push [ebp+08] // our command, which is
a PRIVMSG

* Reference To: CRTDLL.strncmp, Ord:0274h

|
:00405A6C E88F120000 Call 00406D00 // strncmp()
:00405A71 83C40C add esp, 0000000C // fix stack
:00405A74 83F800 cmp eax, 00000000 // strncmp returns 0
if our strings are equal
:00405A77 750A jne 00405A83 // if not jump, it
wont be so we jump to the next one
:00405A79 A1A8A14000 mov eax, dword ptr [0040A1A8]
:00405A7E E9FE000000 jmp 00405B81
:00405A83 6A03 push 00000003 // parameter is 3
again for '433' which is some kind of IRC

* Possible StringData Ref from Data Obj -> "433" // irc servers will
return error code 433 when a NICKNAME is in
// use

|
:00405A85 6881A44000 push 0040A481 // push "433" onto
stack
:00405A8A FF7508 push [ebp+08] // address which holds
PRIVMSG

* Reference To: CRTDLL.strncmp, Ord:0274h
|
:00405A8D E86E120000 Call 00406D00
:00405A92 83C40C add esp, 0000000C
:00405A95 83F800 cmp eax, 00000000
:00405A98 750A jne 00405AA4 // again we will jump
:00405A9A A1B0A14000 mov eax, dword ptr [0040A1B0]
:00405A9F E9DD000000 jmp 00405B81
:00405AA4 6A07 push 00000007 // length of PRIVMSG
is 7

* Possible StringData Ref from Data Obj -> "PRIVMSG"

|
:00405AA6 6879A44000 push 0040A479 // "PRIVMSG"
:00405AAB FF7508 push [ebp+08] // our command which
is "PRIVMSG"

* Reference To: CRTDLL.strncmp, Ord:0274h

|
:00405AAE E84D120000 Call 00406D00
:00405AB3 83C40C add esp, 0000000C
:00405AB6 83F800 cmp eax, 00000000
:00405AB9 750A jne 00405AC5 // this time we WONT
jump
:00405ABB A1B8A14000 mov eax, dword ptr [0040A1B8]
:00405AC0 E9BC000000 jmp 00405B81 // we will jump here
though;)

-
:00405B81 5F pop edi // we jump to the end of
the function, avoiding all the other
// strncmp() checks against the commands filtered
:00405B82 5D pop ebp // and return from the
function
:00405B83 C3 ret

Ok, now it formats your buffer with text again, this time it grabs the IP
address and the COMMAND we wish to do, it then encrypts them both, with
simple, yet different algos:

first here is the call to encrypt them:
:004033B1 8DBDF0F9FFFF lea edi, dword ptr [ebp+FFFFF9F0] //
load ip address
:004033B7 57 push edi
:004033B8 8DBDB0F2FFFF lea edi, dword ptr [ebp+FFFFF2B0] //
load command 'HELP'
:004033BE 57 push edi
:004033BF E87C350000 call 00406940

-

IP ADDRESS ENCRYPTION ROUTINE:

:00406959 FF750C push [ebp+0C] // ip address

* Reference To: CRTDLL.strlen, Ord:0272h // call strlen to
retrieve length

|
:0040695C E887030000 Call 00406CE8
:00406961 83C404 add esp, 00000004
:00406964 8945F4 mov dword ptr [ebp-0C], eax // save
length for counter
:00406967 C745FC01000000 mov [ebp-04], 00000001 // 01 into
pointer ebp-04 this is like for(i=1..)
:0040696E EB2D jmp 0040699D // jump
:00406970 8B7DFC mov edi, dword ptr [ebp-04] // counter
to edi
:00406973 89F8 mov eax, edi // eax=edi
:00406975 B903000000 mov ecx, 00000003 // 3 to
ecx
:0040697A 99 cdq // edx = 0
:0040697B F7F9 idiv ecx // ecx
divided by eax, remainer to edx
:0040697D 8D7415F9 lea esi, dword ptr [ebp+edx-07] //
currently 0, nothing in memory here
:00406981 0FBE1C3500000000 movsx ebx, byte ptr [esi+00000000] // so
ebx is loaded with 0
:00406989 8B550C mov edx, dword ptr [ebp+0C] //
our ip address into edx
:0040698C 0FBE7C17FF movsx edi, byte ptr [edi+edx-01] //
counter+ip-01 into edi is the first char 'd'
:00406991 01FB add ebx, edi //
add ebx and edi to get 0x64 'd'
:00406993 881C3500000000 mov byte ptr [esi+00000000], bl //
save it into what esi points to, for next
time around
:0040699A FF45FC inc [ebp-04] //
increase the counter
:0040699D 8B7DF4 mov edi, dword ptr [ebp-0C] // length
into edi
:004069A0 397DFC cmp dword ptr [ebp-04], edi //
counter
Now I will not get any kind of different value until it loops around the
third time, this is becauuse of the idiv's and edx being 1 and then 2 the
first time around, there is no characters copied to that part of the
buffer
for instance you first have this:

char edxbuffer[10];

every time it loops around it copies a character to edxbuffer and it moves
a character from esi+0 into ebx to be added with edi but the first loop we
have a remainder of 1 and no character at edxbuffer[1] so its 0, same with
the second loop, but the third loop there is no remainder, and we get
edxbuffer[0] added with the third char in our hostname.

At the end of the routine you'll have a table which it uses for the
password encryption, the table consists of three values, mine were CF899A

-
THE PASSWORD ENCRYPTION

:004069A5 FF7508 push [ebp+08] // push password onto
stack 'HELP' ; i sent "HELP HELP"

* Reference To: CRTDLL.strlen, Ord:0272h

|
:004069A8 E83B030000 Call 00406CE8 // strlen()
:004069AD 83C404 add esp, 00000004
:004069B0 8945F4 mov dword ptr [ebp-0C], eax // eax = 4
length of our string
:004069B3 C745FC01000000 mov [ebp-04], 00000001 // set our
counter to 1
:004069BA EB35 jmp 004069F1 // jump
:004069BC 8B7DFC mov edi, dword ptr [ebp-04] // counter
to edi
:004069BF 8B7508 mov esi, dword ptr [ebp+08] // 'HELP'
to esi
:004069C2 8D7437FF lea esi, dword ptr [edi+esi-01] // load
esi with the address pointing to "HELP"
:004069C6 0FBE1C3500000000 movsx ebx, byte ptr [esi+00000000] //
first char of HELP into ebx
:004069CE 89F8 mov eax, edi // eax=counter
:004069D0 B903000000 mov ecx, 00000003 // ecx=3
:004069D5 99 cdq // edx = 0
:004069D6 F7F9 idiv ecx // ecx divided by eax,
remainder to edx
:004069D8 0FBE4415F9 movsx eax, byte ptr [ebp+edx-07] // our
table created from our ip address first
//value = 0x9A
:004069DD B932000000 mov ecx, 00000032 // ecx=32
:004069E2 99 cdq // edx = 0
:004069E3 F7F9 idiv ecx // ecx divided by eax,
remainder to edx
:004069E5 31D3 xor ebx, edx // xor ebx with edx
:004069E7 881C3500000000 mov byte ptr [esi+00000000], bl // first
CHAR of REAL/UNENCRYPTED PASS
:004069EE FF45FC inc [ebp-04] // increase counter
:004069F1 8B7DF4 mov edi, dword ptr [ebp-0C] // we
just compare our counter
:004069F4 397DFC cmp dword ptr [ebp-04], edi //
:004069F7 7EC3 jle 004069BC // same
as before, less than or equal to length
:004069F9 8B4508 mov eax, dword ptr [ebp+08] // save real
password
:004069FC 5F pop edi
:004069FD 5E pop esi
:004069FE 5B pop ebx
:004069FF C9 leave
:00406A00 C3 ret

So basically, it creates a 3 value table with our ip address and then uses
it to unencrypt our password, and then it calls strcmpi on our password
with 'beotch'. So for me I would have to send £êáèĺ which is 0x9C 0x88
0xA0 0x8A 0x8E 0xA7. You can't do this with a regular IRC client, atleast
not one that I am aware of, maybe there is a way... dunno, but i wrote a
little client to send those characters and it works fine, so we can now
get past the first check. Also note, this trojan has 'access levels' there
is beotch, funkers, and joeblow used as passwords, all using the same
encryption which i just explained.

COMMAND ENCRYPTION

Basically, you have your encryped password we just talked about, then
after that is the command which is encrypted as well, Well, ive written a
tool to encrypt your commands so that you can than paste them into the
channel and control the drones, I will release it with the next issue of
hackinthebox. The command encryption isn't as simple as the password
encryption, but it's not very difficult either, just set a breakpoint on
_strcmp() let the first one go by as it is comparing 'beotch' access, when
our password is 'funkers' the second break _strcmp() returns 0, follow the
code from there on in and you should be able to easily defeat the
encryption.

Just for kickz this is "PART #kimmitheb" encrypted, sending this to the
channel on dalnet will cause all the drones to part, but of course I never
told you how to make them all join the channel=)) it's easy though,
hint:(ISON)!

˜™‘•‰ 9niYW.gAyG6/pVgtN.xMTeP.

^^^^^^^
will be different for you of course as it's my password, based on my IP.

I also discovered a NEW version of this trojan, seems pretty much the same
except the author used a file packer on it, the packer used was neolite,
it's very easily unpacked - Simply load up the packed exe in softice
symbol loader, wait for it to break trace until you reach a JMP EAX - EAX
contains the original entrypoint, write it down and then
do a 'a eip' 'jmp eip' and use some kind of memory dumper to dump it, or
just use procdump.. great tool:) After that is done change the entry
point to reflect the REAL entrypoint when it is unpacked which you
obtained from EAX.

Hope you enjoyed it.. im sure there are a TONS of technical errors,
spelling/grammar errors.. etc etc.. =)

metaray

1.) Review: Norton Internet Security 2000 - Dhillon Andrew

2.) Dreamcast Underground - 101Bytez

3.) A look at ASPs (Application Service Providers) - Liquid Sphear

4.) Quake III on Linux - L33tdawg

5.) ID Theft - What they do - Hunterose

6.) Reversing a trojan - metaray!abrams

Source

Tags

Intel

You May Also Like

Recent News

Tuesday, July 9th

Wednesday, July 3rd

Friday, June 28th

Thursday, June 27th

Thursday, June 13th

Wednesday, June 12th

Tuesday, June 11th

Friday, June 7th

Thursday, June 6th

Wednesday, June 5th