Log in

View Full Version : Missing something in this code...


Silver
July 5th, 2004, 15:57
Hey all,

I'm playing with a target, and come across something I don't quite understand.

Scenario. App loads, checks current system time, compares it to a value then messageboxes with "Trial Period Expired". I've tracked down to the call that does the check & decision whether the trial is ok or finished. It calls this code:

Code:

:00416790 55 push ebp
:00416791 8BEC mov ebp, esp

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004167FD(C)
|
:00416793 83EC08 sub esp, 00000008
:00416796 56 push esi
:00416797 50 push eax
:00416798 B8D3605765 mov eax, 655760D3
:0041679D 53 push ebx
:0041679E BB1C684100 mov ebx, 0041681C
:004167A3 51 push ecx
:004167A4 B955000000 mov ecx, 00000055
:004167A9 0003 add byte ptr [ebx], al
:004167AB 05BE71BDBA add eax, BABD71BE
:004167B0 4B dec ebx
:004167B1 C1C00C rol eax, 0C
:004167B4 05EA3B89E8 add eax, E8893BEA
:004167B9 35F815836E xor eax, 6E8315F8
:004167BE 2D5691812D sub eax, 2D819156
:004167C3 C1C004 rol eax, 04
:004167C6 E2E1 loop 004167A9
:004167C8 22FB and bh, bl
:004167CA C20A44 ret 440A



When I step into this code and trace it, it simply sits at the loop instruction and, er, loops . When I execute it, it "magically" jumps out the loop and a messagebox with the trial expired message appears.

I am absolutely sure that this call (code above) is what causes the messageboxa calll - if I trace over the code one level above, and step over the call to 416793, the messagebox appears (ie: it's not the next instruction).

Can anyone give me a pointer of where to go next? Thanks!

ZaiRoN
July 5th, 2004, 16:30
Hi.
The snippet is a simple decryption routine. It decrypts 55h bytes inside the range 4167C7/41681C starting from 41681C. ebx is the pointer to the current byte to change.

ZaiRoN

naides
July 5th, 2004, 17:06
This smells like anti-tracing code:

Two possibilities: The code knows you are tracing, and, while at it, it just goes round and round.

OR

It goes round and round many times so a tracer will quit in despair, then it executes the dirty


The most suspicious, out of the loop reference is

:0041679E BB1C684100 mov ebx, 0041681C
:004167A3 51 push ecx
:004167A4 B955000000 mov ecx, 00000055
:004167A9 0003 add byte ptr [ebx], al

Which bring into the soup memory addresses somewhere else

Put Break points to the end of the loop, and find out who or what is kept on the [ebx] == 41691C address and perhaps it would help you.

Satan

doug
July 5th, 2004, 21:16
End to start self-decryption routine.

Note the important point here:
:0041679E BB1C684100 mov ebx, 0041681C
:004167A3 51 push ecx
:004167A4 B955000000 mov ecx, 00000055

Also notice the apparant "junk" after the loop instruction. RET 440a ?!? where did it use that much stack space?

:004167C6 E2E1 loop 004167A9
:004167C8 22FB and bh, bl
:004167CA C20A44 ret 440A

dig further and notice that: (your decryption parameters)
41681c - 55 = 4167c7
Check whats sits there:

:004167C6 E2E1 loop 004167A9
:004167C8 22FB and bh, bl
:004167CA C20A44 ret 440A

The very last iteration of the decryption-loop seems to patch the "loop instruction" into something else.

If you are using softice, try something like :
BPM 4167C3 X IF (ecx<3)

and carefully trace (using F8) and watch what's going on live.

Silver
July 6th, 2004, 04:00
Thanks for the help guys, that clears things up, I will poke at the code some more later today.

A related question. Now that I know what this code does, I will be able to find the decrypted code & understand what happens. Normally I'd be able to patch some part of the code to prevent the trial from expiring, but I can't do that here.

So, the question. What is the general/accepted method of patching a prog that encrypts the part of the code you want to patch?

The code is clearly stored in the exe, just encrypted. So should I dump the unencrypted code, import it back into the app over the top of the encrypted code, kill the decryption routine and replace it with a call to the unencrypted code? If so, what's the best tool to do that (dump the code & import it).

Just had another thought - I can bpx on MessageBoxA (at which point the code must be decrypted), should I just patch in sice to jmp eip, then procdump it and extract the unencrypted code?

Thanks for the help, didn't expect this app to be so eductional

dELTA
July 6th, 2004, 07:16
Quote:
So should I dump the unencrypted code, import it back into the app over the top of the encrypted code, kill the decryption routine and replace it with a call to the unencrypted code?

Yes, that is a good and common way of doing it.


Quote:
If so, what's the best tool to do that (dump the code & import it).

A hex editor with memory editing capabilitites will work just fine, e.g. Winhex. Copy the decrypted code from memory and paste into the exe on disk.

Silver
July 6th, 2004, 12:29
Thanks as always for the advice

Silver
July 7th, 2004, 13:14
Wow this app is giving me trouble . I sucessfully got the decrypted code from mem pasted over the actual code, and the app runs fine, so that's good. But I've found another trick.

I'd appreciate some confirmation here. I think I've found an anti-tracing technique in this code. I follow the code to this:
Code:
:00416851 EB10 jmp 00416863

That's fine. So I try and follow the call in wdasm, and all hell breaks loose. Looking in the deadlisting, I see this:
Code:
:00416861 80AB8B45FC5E8B sub byte ptr [ebx+5EFC458B], 8B
:00416868 E55D in ax, 5D
:0041686A C20800 ret 0008


That looks really wrong to me, so am I right in thinking this is an anti-trace technique? Making it appear as though the code jumps to the middle of an instruction?

So to fix it, I traced in sice to check nothing else funny was going on (it wasn't). Sice started showing some odd behaviour (ie: it would show the instruction at 416867 correctly, but when stepped over it "magically" changed to "in eax, 5d".

I then nop'd the first 2 bytes, to change the deadlist to:
Code:
:00416861 90 nop
:00416862 90 nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00416851(U)
|
:00416863 8B45FC mov eax, dword ptr [ebp-04]
:00416866 5E pop esi
:00416867 8BE5 mov esp, ebp
:00416869 5D pop ebp
:0041686A C20800 ret 0008


Which (as you can see) has appeared to stop that little problem and let me trace with wdasm.

So, the questions:
(1) Am I right in thinking this is an anti-tracing technique?
(2) Why did sice/wdasm go a bit screwy? Is that normal?
(3) Have I done the right thing by nop'ing the dummy bytes that were causing the issue, or is there a "proper" way to deal with this?

Thanks again. I know I'll be posting again, done all this work and still not found the code that does the expiry check

dELTA
July 7th, 2004, 13:30
If the execution reaches an illegal instruction (or whatever else might be included in the description of "all hell breaks loose" when you debug it but not when you don't, I would guess that your tracing is detected at some point prior to actually getting there, thus directing you to the bad code branch several steps earlier. The "proper" way of fixing this would then most likely be to find and neutralize this initial detection, not starting to nop out bytes at the "payload" (even though this _might_ work too, depending on the implementation of it all).

Silver
July 7th, 2004, 13:45
Hm, I don't think the app has caught me tracing it - I get the same behaviour whether I run it normally, debug it through wdasm or load it through sice.

Handily in this case the app is pretty stupid - if I turn the system clock back a month, it doesn't expire. Turn it forward a month, it expires. Does that change your answer/thoughts somewhat?

edit... Ok, I'm struggling with this app. Anyone kind enough to give me a hand via privmsg where I can say the appname? I really want to understand how to beat this...

dELTA
July 9th, 2004, 06:26
So, does this problem occur only when the app is expired, or always since you fixed the encrypted code, no matter if it's expired or non-expired?

Silver
July 9th, 2004, 06:46
wierd, just got a message saying "Sorry this forum is not accepting new posts".

I see the same behaviour in both my patched version and the original version. I don't believe my patches have altered the behaviour of the app. I've been testing it by pasting my patches into a virgin version of the app, then running it on good and expired dates. I see exactly the same behaviour in both patched and virgin exes; the app works as expected.

I don't have my notes on this app with me at the moment, I'll post further later. Off the top of my head, in C++ terms the app is generating a function pointer somewhere and calling it, which is why I see a call eax instead of a cmp and jne/je etc.

IM-not-so-experienced-O, this app seems to be heavily obfuscated with parts of the code encrypted that don't appear to be relevant to the protection, maybe to cause a lot of wasted time decrypting the wrong thing...

Panemuckl
July 9th, 2004, 08:48
Send me your target and I'll have a look at it. PM the link to DL

doug
July 9th, 2004, 08:51
what you experienced is commonly refered to as "self modifying code"

:00416851 EB10 jmp 00416863

:00416861 80AB8B45FC5E8B sub byte ptr [ebx+5EFC458B], 8B
:00416868 E55D in ax, 5D
:0041686A C20800 ret 0008

Look the jmp target address (416863), and try to find this address in your dead-listing.. it's in the middle of another instruction.

If you check what's _really_ at 416863 (which is what softice did after you jmp'd to it), it starts with the byte 8B. If you are 100% sure that the bytes that are jumped over are not used, you can effectively NOP them like you did.

Use a better disassembler, like IDA. Or code yourself a cleaner if you find this annoying.

And of course, search the board for topics on self modifying code.

Panemuckl
July 9th, 2004, 12:17
Polymorphic as I expected. Alot of protection for a crappy piece of shit like
this. It has several anti-debug checks (better than IsDebuggerPresent) and
creates a thread of itsself (similar to unpacking), that's executed after
creation. So forget WinDasm, you have to use Soft-Ice / Olly.

BTW U don't even have to crack it. Just delete all associated registry keys*
and re-install it after trial.

*) check @ HKEY_CURRENT_USER\Software\<Name of UnH Crappy Solutions>

I've uploaded a nag free copy of your target. Check your PM for the URL.

Enjoy

Silver
July 9th, 2004, 12:21
Hey, thanks for looking at it

Can you explain how you cracked it? I don't really care about the app, I just want to understand how you did it... Thanks!

Panemuckl
July 9th, 2004, 15:29
Quote:
[Originally Posted by Silver]Hey, thanks for looking at it

Can you explain how you cracked it? I don't really care about the app, I just want to understand how you did it... Thanks!


Well, take a look inside the file and recognize the strings:

Code:

Make sure you've enabled all IE Integration items.
There will be no way to do this after the trial period is over!
Purchase the registration key to continue using *** *** after the trial period is over.


At the string, set a hardware BP on memory access (first DWORD). Run!
You'll notice that it won't break as the nag appears. So take a closer look
inside the code. Maybe it's a matter of practise, but soon you'll recognize
some encrypted string

Code:

V291bGQgeW91IGxpa2UgdG8gZG8gaXQgcmlnaHQgbm93Pw

VGhlIHRyaWFsIHBlcmlvZCBoYXMgZXhwaXJlZC4gVG8gY29udGludWUgdXNpbmcgQnJvd3NlciBTZW50aW5lbCwgcGxlYXNlIHJl Z2lzdGVyLg

(some more...)


So set a BP to it, same as above. Run. You'll end up near 0x418a51.
Et voila:

Code:

004189C7 . C68424 9801000>MOV BYTE PTR SS:[ESP+198],12
004189CF . E8 4CDA0000 CALL BrowserS.00426420
004189D4 . 8D4C24 4C LEA ECX,DWORD PTR SS:[ESP+4C]
004189D8 . 68 9C604600 PUSH BrowserS.0046609C ; ASCII "V291bGQgeW91IGxpa2UgdG8gZG8gaXQgcmlnaHQgbm93Pw"
004189DD . 51 PUSH ECX
004189DE . C68424 A001000>MOV BYTE PTR SS:[ESP+1A0],13
004189E6 . E8 35DA0000 CALL BrowserS.00426420
004189EB . 8D5424 60 LEA EDX,DWORD PTR SS:[ESP+60]
004189EF . 68 84604600 PUSH BrowserS.00466084 ; ASCII "QnJvd3NlciBTZW50aW5lbA"
004189F4 . 52 PUSH EDX
004189F5 . C68424 A801000>MOV BYTE PTR SS:[ESP+1A8],14
004189FD . E8 1EDA0000 CALL BrowserS.00426420
00418A02 . 68 144B4600 PUSH BrowserS.00464B14 ; ASCII ""
00418A07 . 8D4424 74 LEA EAX,DWORD PTR SS:[ESP+74]
00418A0B . 50 PUSH EAX
00418A0C . 8D4C24 68 LEA ECX,DWORD PTR SS:[ESP+68]
00418A10 . 51 PUSH ECX
00418A11 . C68424 B401000>MOV BYTE PTR SS:[ESP+1B4],15
00418A19 . E8 529DFEFF CALL BrowserS.00402770
00418A1E . 8D5424 68 LEA EDX,DWORD PTR SS:[ESP+68]
00418A22 . 52 PUSH EDX
00418A23 . 50 PUSH EAX
00418A24 . 8D8424 8800000>LEA EAX,DWORD PTR SS:[ESP+88]
00418A2B . 50 PUSH EAX
00418A2C . C68424 C001000>MOV BYTE PTR SS:[ESP+1C0],16
00418A34 . E8 07ECFEFF CALL BrowserS.00407640
00418A39 . 83C4 40 ADD ESP,40
00418A3C . 8B4C24 40 MOV ECX,DWORD PTR SS:[ESP+40]
00418A40 . 8B00 MOV EAX,DWORD PTR DS:[EAX]
00418A42 . 8B5424 44 MOV EDX,DWORD PTR SS:[ESP+44]
00418A46 . 6A 04 PUSH 4
00418A48 . 51 PUSH ECX
00418A49 . 50 PUSH EAX
00418A4A . 8B4424 38 MOV EAX,DWORD PTR SS:[ESP+38]
00418A4E . 55 PUSH EBP
00418A4F . 52 PUSH EDX
00418A50 . 50 PUSH EAX
00418A51 . C68424 9801000>MOV BYTE PTR SS:[ESP+198],17
00418A59 . E8 32DDFFFF CALL BrowserS.00416790 <--- jmp to code YOU pasted*
00418A5E . FFD0 CALL EAX <-- call you're looking for**


*) returns EAX = address of function User32.MessageBoxA
**) call EAX == call User32.MessageBoxA

Now it should be easy for you to step back to the condition that needs to
be altered. It's at 0x418865 and 0x41886f: JMP 0x418997. From there,
it's not that easy to go on as the actual code (where the condition is polled)
is generated out of the encrypted data.

So do the following: Set a hardware BP on memory access to 0x418865 (the first JMP to 0x418997 == MsgBox("Trial over"). Run!
You will end up in the loop that decrypts the code to offset 0x418865. It's at 0x418238. As you see, a char "5" is taken and encrypted to "0x0F".
This value is written to memory 0x418865. The full command at 0x418865 is like

Code:

00418863 . 3BCA CMP ECX,EDX
00418865 . 0F8F 2C010000 JG BrowserS.00418997 <--- Trial is over
0041886B . 7C 08 JL SHORT BrowserS.00418875
0041886D . 3BF0 CMP ESI,EAX
0041886F . 0F87 22010000 JA BrowserS.00418997 <--- Trial is over
00418875 > 8D4C24 24 LEA ECX,DWORD PTR SS:[ESP+24]
00418879 . E8 6273FFFF CALL BrowserS.0040FBE0
0041887E > 53 PUSH EBX
0041887F . BB 7D884100 MOV EBX,BrowserS.0041887D



All you have to do now is to make sure that both jumps are NOT taken.
But remember: This is not static code, it's dynamically produced by the app!
You will have to find out the corresponding encrypted code of the modified
commands and patch the corresponding offset in the file. Thats what I did.
Hint: the procedure is located at 0x418238

You can also use a loader and patch the bytes as soon as the app reaches the MessageBox call. There are many ways around, so keep practising!

The author did some good job ... hehe... so much energy spent on protecting;
so easy to crack anyway.

Silver
July 13th, 2004, 08:30
Hi Panemuckl!

I saw your original unedited reply before the board went down, so did some work on it and found the jump you talked about in the bit you added. Thanks for pointing me in the right direction, I was too low down the stack

The question I was going to post was "Now that I've found it, how do I patch it?" but you answered that in your edit

Quote:
You will have to find out the corresponding encrypted code of the modified
commands and patch the corresponding offset in the file. Thats what I did.


How did you do it? I have found the block of encrypted code, and I have found the "plain" code that decrypts that block. If I break it with sice, I can patch it in memory so that it works every time.

First I thought I'd break on the end of the decryption loop, dump the app then cut the decrypted code out of the dump and paste it into the target, like I was doing before. Except that from what I've found, the code is cross-decrypted? Ie: 3 different calls decrypt parts at different times? So that doesn't work.

Writing a loader is pretty straightforward, so I'm more interested in how you patched it.

If I was to take a guess, I'd try and find an area of the deadlist that I could use (think that's called a code cave?), write some code into it to patch the jump, then insert a call to that code right after the decrypting loop. But I'm not sure that's the right way to do it.

Can you give me a pointer?

Silver
July 20th, 2004, 12:53
Excuse the bump, hoping Panemuckl will return and fill in the final blank

Panemuckl
July 21st, 2004, 08:19
Quote:
[Originally Posted by Silver]Excuse the bump, hoping Panemuckl will return and fill in the final blank



I already gave you a detailed instruction with all offsets you need to patch, but unfortunately the server was gone just before I clicked the submit button... But that was not my fault, u know

Back to topic... I don't remember the procedure anymore, but I believe I'd just patched this line

00418A59 . E8 32DDFFFF CALL BrowserS.00416790
00418A5E . FFD0 CALL EAX <--- NOP it out


You don't need to patch encrypted code, just bypass the jump to the decrypt+MsgBoxA call. I really don't remember anymore. But if you like, still have the patched exe on my disk. So you can check it out yourself

Silver
July 22nd, 2004, 15:19
Doh, that makes far more sense

Thanks for your help!