Log in

View Full Version : Genetic Algorithms? Debugger Attack? - Brute force exercise part II


ZaiRoN
February 19th, 2003, 17:43
Hi all,

another bruteme from spider. Beware, this new version seems to be not so easy!
You have to reach the congratulation box, Good Luck!

ZaiRoN

ps. you will find a little hint inside readme.txt file

_Servil_
February 20th, 2003, 20:45
Ciao,

Complimenti! Hai trovaro il serialle coretto )

Again, the 'guessing method' with a bit of luck (and ZEN pheeling ;o)) helped me to find the solution,

I find interesting this kind of crackmes, imo less frustrating as usual fishing serial from anoying algo.

regards...

nikolatesla20
February 21st, 2003, 11:45
Since I'm really new at this stuff,

Any small hints would be appreciated.

I've already tried playing around makig inline patches in SI to brute eax, but I get past the first check, but of course then the code is still garbage because of bad xor [edx], eax

So, gotta get my brain working some more...but just a little help to shed light and then I might be able to have a revelation.

Pleeaase?

-nt20

nikolatesla20
February 21st, 2003, 12:17
Hmm.

Now that I look at it, that second time "decryption" is actualy just re-encrypting, and then it jumps out. SO obviously there must be a message box in that encrypted code somewhere, as well as no doubt something to create the message.

So what I'm thinking, now that I read the post to the first bruteme, is that you just have to make up the code yourself for the messagebox, and brute a serial that causes the code to be decrypted to the code you wish. Sort of like programming with a xor decryptor on top....

-nt20

_Servil_
February 21st, 2003, 13:03
Hi nikola,

as I can help, the mentioned messagebox is htere, under bot layers hwoever so you can't rely on the decryption showed in deadlisting 'coz it's continuing, but, there must be at least the second layer decryption in the 1st lawyer only, so need to concern on that.

My first idea was to let it run in loop for all 64k of acceptable variationz with SEHandler treatement but the result was unusable, also I didn't know how to tell kernel to reuse the Handler after it was triggered. Even if I knew, this is not the way to go since the random jumps are jumpping wherever it wants etc etc.

So keeping the focus on how the 2nd decryption loop could look-out is the task (once it's disclosed, the second lawyer is known in the moment aswell).

Kayaker
February 21st, 2003, 14:26
Quote:
Originally posted by _Servil_

My first idea was to let it run in loop for all 64k of acceptable variationz with SEHandler treatement but the result was unusable, also I didn't know how to tell kernel to reuse the Handler after it was triggered. Even if I knew, this is not the way to go since the random jumps are jumpping wherever it wants etc etc.


Hiyas

That was my first thought as well, allow the 2nd decryption layer to run with an SEH handler - when you finally hit the correct s/n the MessageBox would pop up, but as you say the code could resolve to anything and you could jump out of your code to absolutely anywhere, and your SEH no longer applies. I got nice BSODs trying that even though I knew the idea was flawed ;-)

The problem is it's really hard to make assumptions about what the 1st layer decrypts to. In the first crackme it decrypted directly to the MessageBox code, in this one I "assume" that it decrypts to another (hidden) decryption routine and the MessageBox is produced in the 2nd layer.

We can guess that ALL the MessageBox code is revealed in the 2nd layer, but we can't ignore the possibility that the routine might be split between the two, say the correct resource strings are decrypted in the first layer and the push [ebp+08] / Call MessageBox code is revealed in the second. We can't even assume the 2nd algorithm is even a simple xor routine on the same section of code as the first one is really.

Without being able to make an educated (or not) guess on a particular byte pattern which might be produced after the first decryption that you can use as a 'fitness test', it seems to me you'd almost want to be able to *emulate* executing the code after the first decryption to see if it led to a proper decryption of the 2nd and final code layer.

Lol, Still chewing on this one...

Kayaker

nikolatesla20
February 21st, 2003, 14:51
Kayaker, I think you are right, I think _Servil_ was saying that the first decryption layer decrypts to the second decryption algo.

After all, there's quite a few bytes here. ..

SO the only guess would be that the 2 encrypt algo is similar to the first. It's kinda the only thing to go on.

-nt20

nikolatesla20
February 21st, 2003, 16:53
Ok

I think i have a basic bruter working - take a look and see my bugs

I think the code is solid, yes it's "messy" I suppose some might think. VC++ 6.0 with asm statements. I know, I know, hammer to a needle, but hey to each his own.

Probably this will work? I just need to get some bytes to compare with - don't know if my search string is right or not. Right now it doesn't find a match at all.

Good learning anyway.

-nt20

Kayaker
February 21st, 2003, 17:01
Just a quick thought nt20, the serial in eax can be a dword correct?
So
cmp eax, 0x0FFFFFFF
won't cover the entire range?

K

nikolatesla20
February 21st, 2003, 17:09
That's right - I guess I figured it was close enough - and 0xFFFFFFFF is -1 - so maybe I also have to change data type to unsigned long, and then check 0xFFFFFFF0.

LOL my mistake sorry

Plus you might enjoy the lazy hack I made in asm to load the correct data pointers for memcmp

HMM Pretty sure I've got logic error here somewhere -..

-nt20

_Servil_
February 21st, 2003, 17:23
Hello,

looked at the source, you are assuming the 2nd pass is the same. if I can hint try to be less strict and more general. As I think there's no other way as guessing and a bit of luck (or author's intetntion? ). Maybe, more apposite to call it "GuessMe"?

Anyhow it would be interesting if someone can bring any 'infallible technique', if there's so.

regards,
servil

nikolatesla20
February 21st, 2003, 17:29
Yes, for now I was assuming the 2nd would be the same.

SO I am right now going thru and trying different things, such as simple calls, or strings, etc.

I just need to think of a valid search string of data....grr.

-nt20

nikolatesla20
February 21st, 2003, 17:54
Crap the logic is wrong somewhere.

Just take my search int matches and try them in the original program, they are not valid to get past the first check.

hmm

Found the bug. Fixed it.

change the line in the asm

shr eax, 10

to

shr eax, 0x10

DUH

ALso change the check to

cmp eax,0x00000000
jle Outtahere

I've fixed the original attatchment.

-nt20

nikolatesla20
February 21st, 2003, 19:31
fixed another bug - the eax check should be

cmp eax,0x00000000
je OuttaHere


This way eax goes until it rolls over

-nt20

nikolatesla20
February 22nd, 2003, 09:25
I've been guessing my *ss off and getting no where.......

Pretty sure I've got all the bugs out of my bruter now. Just have no idea yet what to look for.

_Servil_, feel like compiling it with the bytes you searched for and seeing if it worx?


I get 65, 535 number matches. The serial is in those somewhere.

-nt20

ryan
February 22nd, 2003, 18:36
Nothing to contribute to here.

Just like to mention that nikolatesla20's willpower and attitude is something I have not seen for a long time in a cracker. Will not let go after taking a bite... something like a bulldog... reminds me of someone I know...

You have my respects, nikolatesla20.

Regards
Ryan

nikolatesla20
February 24th, 2003, 14:17
I have to say, if this whole thing hinges on guessing, then what is the point. I might as well feed the damn thing to a VB program that plugs in the number, and kills the process when it crashes, and just goes thru every combo, which would take about 2.5 days (Running, pluggin number, crashing and killing taking about 3 second estimated time). Of course that's why they call it BFing...

I've tried a few more string guesses- for example, I figured the 2nd decryptor would most likely have to load a pointer, so I searched for 0x11,0x40,0x00 which would be in the code section (it needs to load a pointer to the code section to do the decrypting) but that wasn't found. I find that extremely strange.

I think it's time for a hammer over the head _Servil_, PM me if you want....not asking for handouts, after all, look at all the work I've done so far. Insanity is close.

All is not lost - I have one more idea.

-nt20

_Servil_
February 24th, 2003, 16:45
Hi nikolatesla,


as I tested your code, and it finds !
Just to change the pattern ;o)
So don't give up, the pattern is very simple.

I can provide my source if no success however.

nikolatesla20
February 24th, 2003, 17:13
Ok

That at least gives me hope - like I said I just need to figure out a pattern to search for.


Right now I was experimenting with using a custom debugger of my own that tries each combo - and catches exceptions. If there is an exception it just resets EIP and sets eax to the next value to try. But it hasn't worked yet.

-nt20

nikolatesla20
February 24th, 2003, 17:34
I got it ! yay!


You are right , the pattern is VERY simple...hehehe.... I Finally figured out what to search for - not sure if you looked for the same bytes, so yes, it is partly "luck" I guess too..

Yep, my code worked fine. That's good too, that means I'm not off my rocker...

Thanks for the encouragement _Servil_ !

-nt20

Kayaker
February 24th, 2003, 19:46
Hi All,

Hehe, I know what you (were) saying nt20, I'm going the same route, but I'm not quite ready to declare "Abandon Ye All Hope" quite yet ;-) I'm still testing a brute forcer engine for false positives that I hope will be useful for more than this crackme, but here's my thoughts so far..

Scanning for decrypted bytes that disassemble to an address in the 004011xx range is a good first guess, but I'm sure you've realized that's no guarantee because 1 - the direct address could be created runtime with a simple xor or add, or 2 - the 2nd decryption *could* begin at the end of the decrypt block, which is in the 004012xx range.

We can get a bit more selective than that though with a bit test. What we're really looking for is, as an example,
MOV register, 0040xxxx
or maybe,
lea register, dword ptr [0040xxxx]

For MOV EAX this would be a byte scan for
B8 xx xx 40 00

In explanation, for the MOV statement the one-byte opcode for a 32 bit <MOV Register, immediate address> instruction (mov r32, imm32) ranges from B8h-BFh, for the 8 registers EAX to ESI. The upper 5 bits of the ModR/M byte specifies the Code field, the lower 3 bits the Reg field, i.e.
(mov EAX) = B8h = 10111 000b

The register operand being used is encoded in bits 0-2, therefore 000b indicates the EAX register. The rest are defined by:

EAX = 000
ECX = 001
EDX = 010
EBX = 011
ESP = 100
EBP = 101
ESI = 110
EDI = 111


So, if we know that bits 3-7 will always be 10111b for a (mov r32, imm32) statement, we can use this to be more selective in our brute force algorithm. As an example, this is the bit test I'm developing for this crackme, on the assumption I'm looking for any of 4 byte patterns / statements:

0B8h XX 11 40 00 - mov EAX, 004011xx
0B9h XX 11 40 00 - mov ECX, 004011xx
0BAh XX 11 40 00 - mov EDX, 004011xx
0BBh XX 11 40 00 - mov EBX, 004011xx

Code:

.WHILE ebx != 07FFFFFFFh ; Test all positive integers

; DECRYPT LOOP

; ================
; Fitness Test
; ================

cld
mov ecx, SizeOfDecrypt
mov esi, offset BeginDecrypt ; start of Decrypt block
xor eax, eax

@@:
test ecx, ecx
jz @BruteNext
dec ecx
lodsb ; check each byte

; check <mov r32,
sub al, 10111000b ; mask for opcode MOV in bits 3-7
cmp eax, 011b ; 3 ; selects for eax, ebx, ecx, edx in bits 0-2
jg @B

; check imm32> address
cmp word ptr [esi+1], 4011h ; xx 11 40 00
jnz @B
cmp byte ptr [esi+3], 0
jnz @B

; -----------------------
; Solution Found
; -----------------------
invoke wsprintf, ADDR buffer1, ADDR StringFmt, ebx
invoke SendMessage, hList, LB_ADDSTRING, 0, offset buffer1
invoke SendMessage, hList, LB_SETITEMDATA, eax, esi
invoke UpdateWindow, hWnd

@BruteNext:
inc ebx ; increment serial nummber
;-----------------

.ENDW
jmp ExitOK

; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
BeginDecrypt:
dd 8C47A73Fh
...


You could use this on other possible keywords / byte patterns such as LOOP, the author seems to like those, jmp (Jcc) xx40xxxx perhaps, or popad/ret to end the decrypt block or push ebp to begin it might be useful in other cases.

continued...

Kayaker
February 24th, 2003, 19:48
I use the word Fitness Test because it introduces Genetic Algorithms (GAs) into the mix. There seems to be great potential in using GA's in brute forcers because they can in theory minimize the number of values you have to test, thereby reducing CPU time. The techniques are used with AI, neural nets, fractals, stock market and other types of predictive analysis and so on, and interestingly are modeled to some degree after patterns seen in Population Genetics and Natural Selection. There's much information around about it.

The Bit testing is involved in how the GA is implemented. You start with a random population, in this case serial numbers, and come up with a 'fitness test' to test each one as to how well they fit the type of organism you want to develop (i.e. one or more possible answers). We can use a bit test for this (i.e. select s/n's which produce a MOV register instruction). You test for both the Most fit and Least fit member of your population and kill the Least fit. The Most fit will Reproduce with any remaining member of the population (you can use a fit test to choose the 'best' mate) to produce a new offspring to replace the one we killed (new value overwrites old one in array).

Like in any reproduction, there is a blissful sharing of bodily fluids, resulting in a chromosome exchange or Crossover. In our case this is a sharing of bit values from each parent to produce the new value. You determine where you want the crossover to occur in whatever percentage. Mutations are useful to develop a stable population, so some bit flips can also occur.

You control initial population size, crossover and mutation rate, number of generations, and fitness test to work together to try to produce a convergent population, where there are only one or a few unique values remaining, one of them hopefully your correct serial number. Mathematically it has something to do with defining all the possible local minima from a derivative equation of your fitness test.

I have modeled a simple GA to a very basic protection idea, but it fell far short of a good protection scheme on its own, but I think it could be used as a layer of obfuscation in some manner. You have the power of creating your own life here, a population of select values produced runtime in a non traditional, harder to trace manner for example.

Heh, this got longer than I expected but I've been wanting to bring up the subject of Genetic Algorithms. My biology background got me intruiged by their application to natural populations, and my devilish RE side couldn't help but want to apply them to er, other uses

Perhaps Crypto Mike or someone else has used them in some form or another? This could be a very interesting topic with their applications to AI and other things.

Cheers,
Kayaker

nikolatesla20
February 24th, 2003, 19:55
Very interesting ideas, Kayaker. Yes, that would make sense, to have a "bell curve" of inherited best matches.

Anyway, I also DID test for 00401200 opcodes as well, and of course did not find them. Once I got it decrypted I noticed why....


*Warning* Possible spoiler HINT BELOW do not continue if you want to try it yourself***








My final success was based on a guess that there would need to be a counter initialized somewhere, somehow....



-nt20

ZaiRoN
February 25th, 2003, 06:42
Hi All,

Genetic Algorithms are very popular in these weeks.
I have only read few articles and have not tried to write algorithm about GA kind for which I could be wrong, please correct me :-)

I think that your approach to the problem cannot help us very much in this case. The problem is bound to the way which the Fitness test is executed in; in this phase of the algorithm, you must choose a value for the test like a particular characteristic which must be satisfied (not the solution, a characteristic).
As you said in the previous message, we could use the Mov instruction only working at a few bits of the instruction. This could be a right and interesting choice but who assures me that this instruction is really in the second layer? (the 'MOV register, 0040xxxx' instruction does not exist in the second layer :-p. Obviously, I used this instruction as an example only.)
I think that this is the bound fundamental problem to this Crackme, we do not have certainties on the future and all is based on guessing how the second layer will be. We do not have solid bases on which we can implement an algorithm of this kind.
Quote:
right now I was experimenting with using a custom debugger of my own that tries each combo
This is also an interesting idea. I must admit that also I, like you, have used the guessing way to solve the problem but this morning I have read a solution decidedly better. The guy has written a little program that firstly runs the Crackme and then uses a bruteforce attack. The program sends a serial to the registration dialog. How does it check that the serial is really the right one? After he has sent the serial, the program sleeps for some milliseconds and as soon as he has awoke he checks if the mistake window has appeared. This is repeated until the right serial is found.
What you say!

ciao,
ZaiRoN

nikolatesla20
February 25th, 2003, 09:39
Zairon -

Yes, that is a viable solution, and was what I was going to actually do soon if I kept not getting anywhere - plug each number into the dialog. In fact, I already spit out a text file of all possible matches and had it ready to go

Only then I got a bright idea to try DEBUG_PROCESS and if it got an exception it would reset the EIP to right before the decryption loop and set eax with the next value to try. However, for some reason it doesn't work quite right - seems I get 2 exceptions ? I only worked with it a little while, but it is really fast to do it this way. I still think I might get it working (which would be cool)

Just haven't written debuggers much and so I'm out of practice
But it would sort of work how armadillo does, on an exception, we redirect the program back to a good case scenario.

The only problem I ran into right now is it seems to work - but it locks up at like the 20th number test and I'm not sure why. Perhaps some exceptions are really not recoverable, or maybe it rean out of stack space from some bad pushes that don't get removed. If there is a reliable way to clean the stack I think it would work great.

-nt20

nikolatesla20
February 25th, 2003, 11:20
My debugger is working pretty well - only one problem I need to figure out now.

It no longer locks up, but it does not find the correct code - if I type in the correct code in SI it works. HOwever, it gets to a certain point where the program somehow decides to get a data segment selector of zero. Don't know how that could happen without blue screening me, but it does. (Didnt even know it was possible).

So basically trying to access any memory from then afterward causes mayhem, all illegal access instructions, since the memory data segment doesn't exist.

I wonder if this is part of the stack corruption. I tested one of the lock up numbers and it caused "unknown software exception" which I believe would be stack errors. Could the stack corruption cause DS to be modified? Anyway, it's strange. Gonna try some more stuff. Seem to be getting closer with a generic BF'er for this.

-nt20

Manko
February 25th, 2003, 15:20
Hmm...

I know little to nothing about the stack, so my thoughts may sound stupid and I might have to be set straight...

I first wondered about why it wouldn't be enough just to reset esp to the value it had when attempt started...
Then I wondered if there were values already there that was important or if there were even values there when it had not even been used...

I checked quickly and saw something I actually have seen before but never thought about... There are some sort of selfpointers there when it's not used... never thought about it though...

Anyway last thought was to just save a big chunk of the stack so you could write it back inte the process and reset esp...

Is this a stupid uninformed thought or is this possible/good?

If you think I should do some reading on this; Do you know of any good resources?

Anyway! I'm eagerly waiting to see your next statusreport, and feel free to ignore me if I'm just causing static... :P

/Manko

nikolatesla20
February 25th, 2003, 15:46
Actually Manko, I decided to just restore the stack values to what they were before the crash, hereby fixing the stack.

Basically I walked in SoftICE and just wrote down the values of all the registers at the beginning fo the decryption loop.

Then I just wrote my debugger to restore all of those on any exception, after it resets EIP. This led to a couple more problems, tho.

First, I now could get past any exception without problem. But yet the correct serial would not work when ran in sequence with the rest. I debugged my debugger with SoftICE and found out that some serials cause the thread to almost completely crash with DS segment being set screwy (DS was getting set to zero). Suprisingly, I was able to also restore DS with SetThreadContext with my little Auto-Debugger! (At thread startup, I do a GetThreadContext and get the value of the DS, ES, GS segments, and keep them so I can restore them during an exception). So now I could do anything, after an exception it just keeps truckin'

However, this is the second problem now, and there is no generic way around it. Well, there is, but it's probably more work than it's worth. I got all the exceptions to work great and the debugger rescues very well. BUT some serials cause the decrypted code to form a very big, long loop. Yep, some come out to be LOOPNZ or REPNZ instructions that are HUGE. So they sit there and sit there...lol. 3 ways to fix this would be to see what the decrypted bytes are and nop them during runtime, or re-create the serial match list while looking for LOOP, etc bytes (so you don't get bad serials that cause this), or having another thread time the length between tries, if it's too long, it forces it to continue to the next test.

Well, all 3 of these are just not worth it....for me right now since I've already solved it. Option 3 would be the most generic and effective on other targets other than this one.

Even with that, still when it got to the right serial, some code didn't decypt 100% right and it just caused an exception and hence my debugger kept going on. I haven't investigated why. So it seems there's a lot of problems you have to look out for - the auto-debugger has to recover from a large amount of errors.

So for now I figured it was not a worthy attempt anymore.

-nt20

nikolatesla20
February 25th, 2003, 15:59
Here's the source for the debugger I was playing with. Maybe someone can learn something from it? It's nothing special anyway.. Just your run of the mill debugger.

I didn't get eflags register restoring in there.

The way to use this is:

.5 You need to make a text file with all the possible combinations of serials in it. It's only like 750K or so. You can download one at:

hxxp://webpages.charter.net/nikolatesla20/matches.txt

1. fix the program path to point to where bruteme2 is on your system, and the path to where the matches.txt file is also.

2. Run the debugger.

3. open the serial dialog box and enter a good serial, the first one is 131071. This will cause an exception, and from there the debugger takes over

4. Have fun. Bruting with the debugger is VERY fast, but it doesn't really "work" yet..

-nt20

nikolatesla20
February 25th, 2003, 17:28
After some more testing, it's apparent there needs to be a better way to restore the broken stack. (if its really broken) Hardcode , even if it matches the machine its running on, just won't cut it.

-nt20

nikolatesla20
February 25th, 2003, 17:55
Sorry I'm posting so much, but I just really enjoy this challenge.

I've managed to restore the stack effectively.

The debugger does this by throwing an int3 at the instruction before the decryption loop (This is hit the very first time thru the program). It then catches this int3 and while it's there it grabs what the stack values are and then keeps those for later, to restore when exceptions happen. I also decided to do the same with the register values. Then it restores the INT3 to the original instruction.

Using this I finally got the congratulations box to come up when scanning thru a group of serials.

It still won't work 100% yet on the whole list of serials because like I said, some serials decrypte to infinite loops. But this could also be fixed

It's almost there! Check out the new and improved version.

-nt20

nikolatesla20
February 26th, 2003, 12:38
Debugger attack is functional!

Yep, it works now hehehe

AUTO-DEBUGGER BRUTE FORCER

Here's what I had to do.

Each time we "crash" we need to restore everything we can back to what it was when functional. Hence, we throw an INT3 on the beginning of the decryption loop, and when this fires one time, we pick it up. While we are there, we grab the thread's context so we have ALL the registers, the EFlags, even the DS segment. Also, I grab 200 bytes of the stack.

One other thing we want to do is grab the code of the decryptor routine itself, as well as the IAT table code. Why? Because if we've come up with junk instructions, they could have hosed ANYTHING in the program up, and usually they will. So EACH TIME we have an exception, we need to restore the following:

1. The original encrypted data.
2. The decryptor code loop.
3. the IAT table, since we need this to call messageboxa.
4. 200 bytes of the stack (I just picked the number 200) - just in case
5. All of the registers, and the DS segment.

If we do this, we should be successful at forcing the loop to do our work for us.

Now, what about decrypted code that locks up ? like an infinite loop or a huge string intsruction? How do we fix that?

Easy. We create a seperate watcher thread from our debugger. Each time we encounter an exception and fix the code for the next number test, we set a flag telling the watcher to start watching. I set a sleep time of 1 second on the watcher thread. If the thread gets past this 1 second and sees that it needs to still check status, it forcibly suspends the debuggee, patches an INT3 in the current instruction, and resumes it. This forces the bruteme2 program to generate an exception, which lets the debugger take over again and go to the next number.

It works quite nicely, easily going thru all the number combinations (so far as I've tested).

If you compile this and run it you will definitely find the code you need.

Some people might think that I am giving the debugger too much information - but think, no I am not. I simply tell the debugger to restore the complete state of the program each time an exception occurs. Then I also restore the IAT - since I know that the bruteme2 uses MessageBoxA to show us the message, I can hook into that with an INT3 and watch for that address in my debugger. If that address comes thru, I can assume the decrypted code came out to something valid enought to at least call MessageBoxA, so it is very likely to be the right serial number.

To use:

1. Get the list of Serial numbers
hxxp://webpages.charter.net/nikolatesla20/matches.txt

2. change the path of bruteme2 and matches.txt in the program to fit your system and compile it.

3. run the debugger

4. open "register" in bruteme2 and enter the first serial number, 131071.

5. Press OK and the debugger takes over.

6. Wait for the message to come up that it may have found the serial.

7. Enjoy

BY THE WAY: This works on Win2K and XP. I tested it in 9X and it crashes big time.

-nt20

ZaiRoN
February 26th, 2003, 13:58
Hi nikolatesla20.

I am impressed! You have done a great work!
Did you sleep sometimes?

I would never have thought that it was possible to arrive to talk about debugger-attack and GA with a crackme of this kind. Is someone of you trying to write a genetic bruter?

Best Regards,
ZaiRoN

Kayaker
February 26th, 2003, 17:23
ZaiRoN, I'm not sure if you meant "geneTic" or "geneRic", but I think nt20 may have a handle on the geneRic Very nice nikolatesla (Gauss?), you've been able to execute the code in a protected debug environment. It'll be interesting to see how it works in other cases. It's nice to see some debugger code. You could maybe tie the bruteforcer.cpp and the debugger engine together in memory with linked lists for example so you could code the bruteforcer algo a la plugin for different situations.

I wonder how using DEBUG_PROCESS compares to instead hooking directly the interrupts likely to be called during an error when the decrypted code is executed? If Hooking exceptions via the IDT are done in ring3, the handler uses the current stack, but if done in ring0, there's the benefit that in a privilege change there's a stack switch which saves the current EFLAGS, SS, ESP, CS, EIP, and error code information to the handlers stack. The correct stack could be restored this way.

You'd have to write or patch in code, one interrupt to be a control INT (say INT 6) in which you could save the stack info as it was immediately before you begin executing the decrypted code. Then you return control and allow the code to run, catching any faults. Pretty much as you're doing with INT3 I suppose, the difference seems to be using DEBUG over direct IDT patching afterwards. Like with anything, you'd be likely to encounter initial problems with this approach too.

One thing critical in hooking an interrupt is disabling all other interrupts with CLI and restoring them with STI within your handler code to prevent reentrancy issues (very bad!). Does the DEBUG_PROCESS debugging event code take account of this nt20?


This is a good thread. Lol, I'm still working on the GA angle It may not be as applicable to this crackme, because as was said this is more of a Guess-me in the final analysis. If you had a more defined algorithm to work with, a more genetic approach might be able to be used. After the first little filter algorithm of the crackme you've already got a finite population of answers to start with, including the correct one, and you need to test them all for the second decryption part. If you hit the right fitness test then yes, I think you could use the GA idea to isolate the correct s/n. But then you still have to test the answer in some form which means a visual inspection/trial, or run it through nt20's debugger.

The first small algo has too many solutions to be viable for GA I think, it would take you too many Aeons of generations to produce the correct population of possibilities. This part at least can be separated out from the rest of the decryption stuff, and creating a simple loop to run the code and save the results would make any easy bruteforcer project for anyone still interested in it. Using these results to test out the second decryption layer is the more difficult part.

Nice work.

Cheers,
Kayaker

nikolatesla20
February 26th, 2003, 19:14
Well, there does exist I believe the possiblity to create this into a more "generic" active debugger - but then it would be somewhat like an unpacker, except it's for encrypted code

In fact, an approach like this would be pretty handy for active encrypted code - for example, where you may have no idea what the code should look like, but you know what is communicates with. For example, I knew that it would communicate with MessageBoxA, so I could sit and watch that call, while walking over any faults. You will get there eventually no matter what because of this. A similar technique could no doubt work in other programs.

The debugger is messy right now - the addresses are hardcoded (OEP could be gotten from the file, and address to watch could be in an INI or something). Also, I just realized that it might also be more efficient to just restore a nice big block of code each time, rather than all these seperate arrays. (Just grab a big chunk). But hey whatever works.

I belive DEBUG_PROCESS is ok Kayaker, because it freezes the entire process and all its threads. You basically have full control from there. The only thing is, this may not be very effective on any type of program that "debugs itself" (but then what is).

I've tried some of these techniques on armadillo protected apps, and really gotten nowhere as well...hmm. But there are other techniques of course. This whole concept is more suited for forcing a decryption of a specific block of code, rather than running a whole program thru it. You could probably even get away with forcing the program's EIP directly to the code of interest right away, if you've pre-stored all the right values (like maybe have a "watch" cycle that just starts the program and watches it, and then kills it and restarts it or something.)

I really found this enjoyable, mainly for the fact that yes, it's good to see debugger code With so many protections using such code to "protect" themselves, the more experience you have with such code the better..and then you may be able to code good unpackers, etc, as well

Something I'd like to become proficient at doing

Of interest - WindowsXP has some new debugger features, for example, it is now possible to attatch to an active process, debug it, and then DETACH WITHOUT TERMINATING THE PROCESS. That is nice. Plus you can now do a "DebugBreakpointProcess" in XP, whereby you can cause a debug breakpoint exception in another process ! Haven't experimented with it at all yet tho, but it would save having to writeprocessmemory yourself eh? Just suspend the thread (maybe you have to do so, not sure, maybe you dont!) and then call that function and resume. So you could attatch to an active process, and force it to have a debugbreakpoint so you could break in ....



-nt20

obitus
February 26th, 2003, 23:26
Here is a C version of the bruter that works. Fill in the searchData it is a character array so : 0xFF, 0xCA, etc.

I guessed what to search for based on someone else's post, in regards to having to initialize a counter.

obitus

evaluator
March 11th, 2003, 01:13
Hello, there!

yeah! I try read upper 3kg english..

Nikola!
I plane for you XMM crackme!!!
Confirm, have you PIII (cel) CPU?

nikolatesla20
March 11th, 2003, 09:24
Yes I have intel PIII 550 Mhz

-nt20