Log in

View Full Version : Harlequins Task 3 Challenge


Kayaker
May 21st, 2001, 00:11
Hi All,

Mitrix posted a question on one of the tasks in Harlequin's course. After looking at it I thought it was so good that I thought it'd make a great Project. Since it's actually the final task of a section and I think the course should be started from the beginning without giving away the answers to the previous task, I deleted the original link Mitrix had posted and will just post the download link for Task 2/3:

http://htasks.cjb.net/fx23ht.zip

In case of difficulties (I couldn't d/l it with Opera), I'll attach it here (11KB zip)

Here is what Harlequin says about this task:

"I should warn you here though, this is the last Task in this section and as such is therefore the most difficult. Some may struggle with this one a little. I can only assure you that in the CodeWoods things are not always as they seem, there is (despite everything you may think) a solution to this task and, if you have made it this far you have more than the skills required to complete it successfully."

The rest is self-explanatory, find the correct serial number. I've posted Mitrix's original post and my reply.

I encourage you to try the complete course, which begins at:

http://www.angelcities.com/members/harlequin/

Good Luck,
Kayaker

Kayaker
May 21st, 2001, 00:12
ORIGINAL POST (slightly modified):

In the program the DD [0040209F] is 00401124 and the [00401124] is E8. I think it should be EB.

:00401124 E8B5000000 Call 004011DE
:00401129 83F80A cmp eax, 0000000A
:0040112C 757B jne 004011A9
:0040112E BAA7204000 mov edx, 004020A7
:00401133 33DB xor ebx, ebx \
:00401135 8A1A mov bl, byte ptr [edx] |
:00401137 42 inc edx |
:00401138 33C0 xor eax, eax \the first serials must 4
:0040113A 8B0D9F204000 mov ecx, dword ptr [0040209F] /
:00401140 8A01 mov al, byte ptr [ecx] |
:00401142 80F3DC xor bl, DC |
:00401145 3AD8 cmp bl, al /
:00401147 7560 jne 004011A9
:00401149 8A02 mov al, byte ptr [edx]
:0040114B 42 inc edx
:0040114C 3430 xor al, 30
:0040114E C1E008 shl eax, 08
:00401151 8A02 mov al, byte ptr [edx]
:00401153 42 inc edx
:00401154 3430 xor al, 30
:00401156 C0E004 shl al, 04
:00401159 66C1E804 shr ax, 04
:0040115D 8A1A mov bl, byte ptr [edx]
:0040115F 42 inc edx
:00401160 2AC3 sub al, bl
:00401162 3C3C cmp al, 3C
:00401164 7543 jne 004011A9
:00401166 B104 mov cl, 04
* Referenced by a (U)nconditional or ©onditional Jump at Address:
|:00401178©
|
:00401168 8A02 mov al, byte ptr [edx]
:0040116A 42 inc edx
:0040116B 3433 xor al, 33
:0040116D 2C03 sub al, 03
:0040116F 3AC1 cmp al, cl
:00401171 7536 jne 004011A9
:00401173 FEC9 dec cl
:00401175 80F900 cmp cl, 00
:00401178 75EE jne 00401168
:0040117A 668B02 mov ax, word ptr [edx]
:0040117D 663D3033 cmp ax, 3330
:00401181 7526 jne 004011A9
:00401183 A0A7204000 mov al, byte ptr [004020A7]
:00401188 3C37 cmp al, 37 ; the first serials must 7
:0040118A 751D jne 004011A9
:0040118C 6A00 push 00000000

Kayaker
May 21st, 2001, 00:14
Hi Mitrix,

Looks that way doesn't it? As you mention, the 1st part of the algorithm

:00401124 E8B5000000 Call 004011DE ;GetDlgItemTextA
:00401129 83F80A cmp eax, 0000000A ;length must be 10
:0040112C 757B jne 004011A9
:0040112E BAA7204000 mov edx, 004020A7 ;your entered s/n
:00401133 33DB xor ebx, ebx
:00401135 8A1A mov bl, byte ptr [edx] ;1st char of s/n
:00401137 42 inc edx
:00401138 33C0 xor eax, eax
:0040113A 8B0D9F204000 mov ecx, dword ptr [0040209F] ;address 401124
:00401140 8A01 mov al, byte ptr [ecx] ;1st byte of opcode (E8 )
:00401142 80F3DC xor bl, DC ;xor 1st char s/n w/ DC
:00401145 3AD8 cmp bl, al ;must be = E8
:00401147 7560 jne 004011A9

If 1st char XOR DC = E8
then
DC XOR E8 = 1st char = 34h = 4

The 1st char MUST be 4 then. However, the last part of the algorithm indicates it MUST be 7:

:00401183 A0A7204000 mov al, byte ptr [004020A7]
:00401188 3C37 cmp al, 37
:0040118A 751D jne 004011A9


Can't be both. Harlequin must've goofed. Nope. (I love this guy's work


You followed the algorithm perfectly and came to the conclusion Harlequin wanted you to come to. As a matter of fact, I like this one so much I hope you'll forgive me if I move it to the Mini Project Forum, I think it'll make a great project and there's some interesting instruction to come out of it.

Regards,
Kayaker

CoDe_InSiDe
May 21st, 2001, 07:19
Hi Kayaker,

I've taken a look at this and i know this guy's work it's always quite funny
But anyway, i don't know if you have a valid Serial but i have a valid "bugged" Serial ;D
I'm not going to tell more, i think
Just tell me if you got that too....?

Cya...

CoDe_InSiDe

Clandestiny
May 22nd, 2001, 08:17
Hi Kayaker,

Not quite the garden variety serial fishing / key gen exercise, but you wouldn't know it until that little caveat at the end

So far I've generated a serial that passes all checks but the last... But I have made a couple of observations about both the first and last checks (ie. the significance of E8 vs. EB). Interestingly, I noticed that in the following lines ecx actually holds the pointer to an address within the proggy's code section.

:0040113A 8B0D9F204000 mov ecx, dword ptr [0040209F]
:00401140 8A01 mov al, byte ptr [ecx]

This address corresponds to
:00401124 E8B5000000 Call 004011DE

And hence you get your E8 from the hex opcode for "call" in the function call to GetDlgItemTextA. Now in the last check, we'd rather this E8 be EB because this would allow the first check to pass with a 7 (ie 37h) rather than a 4 (34h). Making this realization, I looked up what EB is in my asm hex opcode reference and its apparently a jmp command. So the only thing I can come up with as of yet to make a valid serial is to change the instruction at address 00401124 from a call to a jump. BUT I'm not quite sure that you can jump directly to an API like GetDlgItemTextA because you would ultimately need to jump back to the correct position in the code from where you made the original jump in order to continue execution since a jump doesn't return like a call does. I haven't actually tried this yet, but I guess you could maybe write a patch that simulates the process that occurs when a call is executed (ie. saves the instruction pointer on the stack and then jumps to the address where GetDlgItemTextA begins in memory. According to my asm reference, the RET instruction just pops the previous instruction pointer off the stack right back into eip so execution can resume where it left off. Anyway, I'm just speculating here.

And assuming, you could make it work by changing the instruction I'm not even sure if this observation is on the correct path to a valid serial because it would be necessary patch the .exe to do it.

So, here are my 2 questions (and I don't want the solution yet... just a little guidance / reaffirmation)....
1) Is any kind of patching allowed ??
2) Am I looking in the right direction or do I need to completly revise my strategy ??

If no patching is allowed at all, I'm gonna be really stumped

Regards,
Clandestiny

PS: Kayaker, that last post of yours in Code_Inside's crackme was a really impressive explanation on how to rebuild a PE file ! Just wanted you to know that it was very helpful and that I haven't given up on it yet. Gotta hit the PE docs again. ....Just got a little distracted in the last couple of days

Clandestiny
May 22nd, 2001, 10:02
Me again,

...After a little more investigation.

I think I may have answered my own question from above. I don't think I'll be able to patch in the way I was thinking simply because I just realized something about the EB opcode. Not only is EB an opcode for jmp, but moreover it is the opcode for a SHORT jump. Alas, a short jump won't get me to the empty space at the end of the code section to insert my patch. Guess I'll have to keep thinking

Clandestiny

Kayaker
May 22nd, 2001, 10:20
Quote:
Clandestiny (05-22-2001 06:17):

1) Is any kind of patching allowed ??
2) Am I looking in the right direction or do I need to completly revise my strategy ??


1) No
2a) No
2b) Yes

;D

Clandestiny
May 22nd, 2001, 12:52
Hiya Kayaker,

hehehe

I got the serial! And man do I feel stupid now :-o

Oops, I swallowed Harlequin's bait (and then some) !

I'd post my solution, but I don't want to ruin the fun for anyone else who might be trying it. Besides, there's really not that much to write about once you get the point of it ;-) As some wise man said, "to assume makes an ass out of you and me (although its only me in this case)" ...A very good lesson.

Cheers,
Clandestiny

NeO'X'QuiCk
May 22nd, 2001, 19:19
Kayaker the idea is good!I think its not so hard for newbies but they will loose some time with this like Clavidestina did for nothing !heh

This task is very common for apps and crackmes!If they think good they will see the solution alredy posted by you.They only need to read harder and they will put two and two together.

It was nice working on it !heh but i found serial soon so better luck next time !

I think i will join the course to see !Is it hard Kayaker ??

NeO'X'QuiCk

Kayaker
May 23rd, 2001, 00:09
Hi,

You're right Neo, the real answer isn't particularly hard to find if you have a suspicious mind and look beyond the obvious. Once the obvious becomes suspicious that is

But what I found interesting wasn't the "trick" per se, but, because this is such a simple program, you can easily follow how the trick *works*, how it is implemented from a programming point of view. This is the kind of program one could truly "reverse engineer" and create workable source code from.

For example, the code at the program entry point is:

:00401000 PUSH 00
:00401002 CALL KERNEL32!GetModuleHandleA
:00401007 TEST EAX,EAX
:00401009 JZ 00401026
:0040100B MOV [0040209B],EAX
:00401010 PUSH 00
:00401012 PUSH 0040102D ;entry point of DlgProc
:00401017 PUSH 00
:00401019 PUSH 64 ; DialogID_0064 seen in W32Dasm
:0040101B PUSH DWORD PTR [0040209B]
:00401021 CALL USER32!DialogBoxParamA
:00401026 PUSH 00
:00401028 CALL KERNEL32!ExitProcess

If you've done a bit of ASM programming you'd recognize this as the skeleton of a modal dialog box:

.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke DialogBoxParam, hInstance, ADDR DlgName, NULL, ADDR DlgProc, NULL
invoke ExitProcess,eax

...continued...

Kayaker
May 23rd, 2001, 00:11
The next section is the DlgProc itself and you can see the Windows messages being processed:

:0040102D ENTER 0000,00
:00401031 PUSH EBX
:00401032 PUSH EDI
:00401033 PUSH ESI
:00401034 CMP DWORD PTR [EBP+0C],02 ;constant for WM_DESTROY
:00401038 JZ 00401040
:0040103A CMP DWORD PTR [EBP+0C],10 ;WM_CLOSE
:0040103E JNZ 00401044
:00401040 JMP 00401068
:00401042 JMP 0040105F
:00401044 CMP DWORD PTR [EBP+0C],00000111 ;WM_COMMAND
:0040104B JNZ 00401051
:0040104D JMP 0040108E
:0040104F JMP 0040105F
:00401051 CMP DWORD PTR [EBP+0C],00000110 ;WM_INITDIALOG
:00401058 JNZ 0040105F
:0040105A JMP 004010DD
:0040105F XOR EAX,EAX
:00401061 POP ESI
:00401062 POP EDI
:00401063 POP EBX
:00401064 LEAVE
:00401065 RET 0010
:00401068 PUSH 00
:0040106A PUSH DWORD PTR [EBP+08]
:0040106D CALL USER32!EndDialog
:00401072 PUSH 00
:00401074 CALL KERNEL32!ExitProcess


And it looks like the source could be represented with something like:

DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

.IF uMsg==WM_DESTROY || WM_CLOSE
invoke EndDialog, hWnd,NULL
invoke ExitProcess,NULL

.ELSEIF uMsg==WM_COMMAND
JMP 0040108E ;this is where it gets interesting

.ELSEIF uMsg==WM_INITDIALOG
JMP 004010DD ;whatever initialization code is used

...continued...

Kayaker
May 23rd, 2001, 00:13
The jump to 40108E when the WM_COMMAND (111) message is received is where it gets interesting because this is Self Modifying Code (SMC).

:0040108B ADD [EAX],AL
:0040108D ADD [ESI-7D],AH
:00401090 JGE 004010A2
:00401092 INSB
:00401093 JNZ 0040109D

becomes

:0040108E CMP WORD PTR [EBP+10],6C ;button pushed?
:00401093 JNZ 0040109D
:00401095 PUSH DWORD PTR [EBP+08]
:00401098 CALL 0040110F
:0040109D CMP WORD PTR [EBP+10],6B ;edit box received input?
:004010A2 JNZ 004010D6
:004010A4 MOV EAX,USER32!GetWindowTextA
:004010A9 PUSH 00000080
:004010AE PUSH 00402127
:004010B3 PUSH DWORD PTR [004021AB]
:004010B9 CALL EAX ;GetWindowText of edit box
:004010BB CMP DWORD PTR [00402127],73704F4F


Rather than just blindly flailing away at a crackme until you get the right answer, here is where you can use your knowledge of how Windoze operates to *understand* how the crackme works, and use other clues to assist you.

After the uMsg parameter of a Windows message is processed, in this case 111 for WM_COMMAND, the other parameters may be processed.

WM_COMMAND
wNotifyCode = HIWORD(wParam); // notification code
wID = LOWORD(wParam); // item, control, or accelerator identifier
hwndCtl = (HWND) lParam; // handle of control

In the code above, the ControlID's in wParam are being examined. W32Dasm itself tells you that 6C and 6B are the ControlID's for the button and for the edit box:

002 - ControlID:006C, Control Class:"BUTTON" Control Text:"Try It!"
004 - ControlID:006B, Control Class:"EDIT" Control Text:"Your Serial"


If you set a 'BMSG hwnd WM_COMMAND' breakpoint in SoftIce on the hwnd of the main window, you'll break when either control receives input. For example,

:BMSG 0690 WM_COMMAND
Break due to BMSG 0690 WM_COMMAND (ET=1.83 seconds)
hWnd=0690 wParam=006B lParam=01000694 msg=0111 WM_COMMAND

From this break you can trace back into program code and follow the action...

By being able to understand what ALL the code in a program is doing, even the boring looking stuff, you've got a better chance of finding where the real protection lies. Here, does something happen only when you push the button, or is there a hidden check when you type something in the edit box? This seems to be a popular deception with Delphi programs where the programmer can use an OnChange Event as you're typing your s/n into the registration edit box. There's another nifty bit of SMC that opens the final door if you successfully pass the real protection check above.

So the point is not to just come up with the quick answer, but like Clandestiny (sp?) ^_^ "waste" the time, examine all angles, including fancy patching, and try to *understand* the code, learning all the while.

Cheers,
Kayaker

Clandestiny
May 23rd, 2001, 08:21
Hi Kayaker,

Heh, I guess I lacked "zen" in my approach to this one but I actually found the real solution while reading my whole 8 page disassembled listing. After you told me patching was not an option, there was NO logical solution to that serial check routine and I knew I had to look elsewhere... Of course, after comprehending the protection I realized I'd REALLY missed the obvious in the list of imports

And you're right, the program is actually quite small and easy to follow and therefore would not be impossible to re-engineer / recode. So here's my suggestion... Why don't we extend the scope of this project a bit ??

Part 1 could include reverse engineering and rewriting the complete source code of Harlequins crackme from the dead listing (only 8 pages) in a language of your choice...

And Part 2 could include inventing a clever way to modify Harlequin's crackme / improve the protection.

Well there's my 2 cents for now ;-)

Regards,
Clandestiny

NeO'X'QuiCk
May 23rd, 2001, 16:25
heh True Kayaker what can i say !But i think that if newbies would like to learn they should join the course !Because i think they can must to learn from simple step to hard one.

Because so fare i didnt find i really good course and that would teach you from step to step but only course when you show you knowledge if you have it.If not the learn and come back.SO this kind of courses are ment for good coders and crackers and their main good is to put more ppl to quite it!

But this one i like because i give you all tuts and tools to do it!You must just use some brains !!heh



NeO

Kayaker
May 24th, 2001, 23:31
Hi,

Sounds like an interesting challenge Clandestiny. I'm going to give it a shot as soon as I get a chance. I've got a little "trick" in mind that I'd like to see if it works just for fun.

If anyone tries the rest of Harlequin's course and has any questions, maybe we can start a project thread on it too.

Kayaker

Clandestiny
May 25th, 2001, 19:36
Hi Kayaker,

My reversed and recoded version of Harlequin's crackme is coming along quite well, but there is one silly little bug that is driving me crazy. ...And that's the Bitmap resource.

Now, I could easily load the bitmap using LoadBitmap() and then paint it into the client area by getting a device context and using BitBlt() in response to the WM_PAINT message... BUT I'm trying to keep this as "authentic" as possible and thats clearly not what Harlequin did to load his Bitmap (as evidenced by the imports in WDASM).
Indeed, there appear not to be any GDI functions of any kind. So I'm presuming that there is some way to load the bitmap direct via the resource file ??? I've examined the resource file from Harlequin's crackme in detail and I just can't quite seem to figure it out... I don't even see any mention of the Bitmap's resource identifier in my dead listing. Admittedly my Win32 asm programming skills are limited, but I'm unsure how load this thing w/o any GDI APIs. Likely, there is some insanely simple way to do this and I'm going to shoot myself in the foot for asking about it when I find out... but a little insight will be appreciated anyway ;-)

Thanks :-)
Clandestiny

Kayaker
May 26th, 2001, 00:26
Hi Clandestiny,

I had a bit of a problem with that one too. Working with .rc files is still a bit of a black art

I extracted the .bmp and .ico with ResHacker and produced an .rc file from the original exe with BRW. After the usual messing around to get MASM to recognize it, I had the same problem with no bmp in the static edit control. Finally got it right:

======================================
#include "resource.h"

#define BITMAP_1 104
#define IDC_EDIT_REG 107
#define IDC_BUTTON 108

BITMAP_1 BITMAP "Harl.bmp"

ICON_1 ICON "Harl.ico"

100 DIALOG 0, 0, 128, 105
EXSTYLE 0x200L
STYLE DS_ABSALIGN | 0xA04L | WS_OVERLAPPED | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION " "
FONT 8, "Times New Roman"
BEGIN
CONTROL "", 102, "STATIC", SS_BLACKRECT | WS_CHILD | WS_VISIBLE, 0, 0, 131, 137
CONTROL "Try It!", 108, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 1, 90, 124, 12, 0x200L
CONTROL "", 101, "EDIT", ES_CENTER | ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_BORDER, 1, 35, 124, 38, WS_EX_NOPARENTNOTIFY
CONTROL "Your Serial", 107, "EDIT", ES_CENTER | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 1, 75, 124, 10
CONTROL 104, 106, "STATIC", SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE | WS_CHILD | WS_VISIBLE, 1, 3, 124, 28
END
=====================================

Then I used a standard modal dialog template from Iczelion's ASM tut #10-2, and filled in a few of the apparent calls in Harlequin's app within this framework:

====================================
.386
.model flat,stdcall
option casemap:none
DlgProc PROTO : DWORD,: DWORD,: DWORD,: DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data?
hInstance HINSTANCE ?

.const
MYDIALOG equ 100

.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke DialogBoxParam, hInstance, MYDIALOG, NULL, ADDR DlgProc, NULL
invoke ExitProcess,eax

DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

.IF uMsg==WM_DESTROY || uMsg==WM_CLOSE
invoke EndDialog, hWnd, 0
invoke ExitProcess,0

.ELSEIF uMsg==WM_COMMAND

.ELSEIF uMsg==WM_INITDIALOG

.ENDIF

xor eax,eax
ret
DlgProc endp

end start
====================================

The above code produces a dialog virtually identical to the original, just needs the details filled in now

Kayaker

Clandestiny
May 28th, 2001, 15:57
Hi Kayaker,

Thanks for the pointer. I had no idea you could load a bitmap in the resource file like that. Sure is handy though... and to think I've been writing all that extra code to paint bitmaps into a window's client area for nothing... Likewise, I'm glad I decided to write this in asm since I found out that Borland's Resource Workshop beats VC++'s by a long shot

Right now I've got the reconstructed program and its working great minus SMC. I don't suppose you know anything about writing SMC, Kayaker ?? ;-)

Cheers,
Clandestiny

Kayaker
May 28th, 2001, 22:04
Hi Clandestiny,

Just been thinking about posting an update myself. I'm at the same stage. I'm leaving the final SMC details until I finish, er, "enhancing" the proggy with a new protection

There's 2 tricky sections I see, one SMC, the other I guess you could call obfuscation. BTW, I actually goofed in my earlier post thinking the line
:0040108E 66837D106C cmp word ptr [ebp+10], 006C
was part of SMC code. The obfuscated section is just above it and I had done a screendump in SoftIce of this section and SI didn't parse the code correctly. WDasm does show it properly however.


Anyway, the obfuscated (that word really doesn't roll of the tongue easily code is at:

:00401079 6880000000 push 00000080
:0040107E 6835674000 push 00406735
:00401083 FF35AB214000 push dword ptr [004021AB]
:00401089 0000000000 BYTE 5 DUP(0)

This code is never called. If you look down a little further you see the PUSHes repeated with an indirect call to GetWindowTextA:

:004010A4 B8E4114000 mov eax, 004011E4
:004010A9 6880000000 push 00000080
:004010AE 6827214000 push 00402127
:004010B3 FF35AB214000 push dword ptr [004021AB]
:004010B9 FFD0 call eax ;GetWindowTextA

And 4011E4 is the address of the jump table entry for this API:

* Reference To: USER32.GetWindowTextA, Ord:0000h
|
:004011E4 FF2584304000 Jmp dword ptr [00403084]


So what I've got right now is a direct Invoke of GetWindowTextA at 401089 so the API will be included in the import table. Then I guess the trick is to hex edit it out later and include the code which will call it indirectly.

...continued...

Kayaker
May 28th, 2001, 22:05
The SMC is of course right below the obf. section:

:004010BB 813D272140004F4F7073 cmp dword ptr [00402127], 73704F4F
:004010C5 B8D0104000 mov eax, 004010D0
:004010CA C7000F84B600 mov dword ptr [eax], 00B6840F
:004010D0 C7000F840000 mov dword ptr [eax], 0000840F

which converts to the proper code of:

:004010BB 813D272140004F4F7073CMP DWORD PTR [00402127],73704F4F
:004010C5 B8D0104000 MOV EAX,004010D0
:004010CA C7000F84B600 MOV DWORD PTR [EAX],00B6840F
:004010D0 0F84B6000000 JZ 0040118C ;good boy MessageBox

Sooo, I guess 4010D0 is the line to change, the next line has the bytes to move there, and the original 4010D0 is just bogus, but holds a place for 6 bytes. The tricky part seems to be planning and thinking ahead and knowing what bytes will create the code line you want. I guess the 'a' command in SI is handy for this.

I don't know, I've never created SMC before. Maybe someone who's played with this can give us a few pointers. Hell, this'd be a great topic in itself.

Unless you change the code characteristics in the compiled file later, you need to include this in your linker line:
/SECTION:.text,EWR
This will create a .text section with the characteristics E0000020, which will allow the SMC to write to memory without crashing.


BTW, how did you deal with the wm_command loop? In the original file, the loop continues, somewhat ungracefully, after the good message box, which is why you see it flickering. The reason for this I think is that there are *2* wm_command messages processed for every letter you input in the edit box. I've got a little proggy (ISpy) that monitors windows messages and tells me this. In my version the loop finishes with a crash I added a flag which tests if the good messagebox has been called, in which case stop processing messages from that edit box. This works great, but isn't how the original code ran.

So where the heck is everybody else? They're missing all the good, clean fun ^_^

Cheers,
Kayaker

Clandestiny
May 29th, 2001, 22:25
Hiya Kayaker,

I think I figured out SMC and its not half as bad as the horrors I'd conjured up in my imagination prior to trying it. In fact, its really cool (and amazing) to me that you can actually do something like this with asm.

Here's the little piece of SMC I've managed to write so far...

Test1:
mov edi,offset smc1 ; define the beginning address of the code you want to replace
mov [edi],byte ptr 080h ;replace code w/ hex opcodes for new instructions
inc edi
mov [edi],byte ptr 0F3h ;replace code
inc edi
mov [edi],byte ptr 0D2h ;replace code
smc1: xor bl,0DCh

/*********************************
xor bl,0DCh is a 3 byte instruction and we replaced it with a 3 byte instruction
xor bl,02Ch
**********************************/

mov edi,offset smc2 ;address of code we want to replace
mov [edi],dword ptr 04E8C166h ;replace code
smc2: cmp ax,03330h
xor ebx,ebx
mov esi, offset serial
.
.
.
/*********************************
Here we replace a 4 byte instruction cmp ax,03330h with another 4 byte instruction shr al,04
*********************************/

So from this I've deduced a general procedure...

1) Define a label where you want your SMC to start and load the address of that location in a register
2) Determine the number of instructions you want to replace and calculate the total number of bytes used by those executable instructions
3) Load in the new instructions starting at the address you defined to be the beginning of the SMC code until you've reached the total number of bytes of the instructions you've designated for replacement
4) Change the section characteristics to E0000020h (like you mentioned previously)

Well, thats all I've discovered so far, but I think it will be servicable for the task at hand

Oh, and in case you're interested I'll post the urls to the 2 documents I managed to dig up to help me figure this out (though IMO they're a bit skimpy on the explanation).

http://blacksun.box.sk/smc.txt
http://www.geocities.com/SiliconValley/2151/selfmod.html

Just don't get too excited and go overboard with the SMC in your "enhanced" protection, Kayaker ;-)

Cheers,
Clandestiny

Kayaker
May 31st, 2001, 02:48
Hi Clandestiny,

I liked your idea of using the OFFSET of the label of the line which is to be SMC'ed in ASM code. Saves having to input it or hexedit it in later once all the coding is finalized.

In the 2nd step however you still have to manually calculate the opcode and displacement bytes and MOV them as a hex value. I wanted to see if this could also be done entirely as ASM coding and came up with this.

If you know the conditional jump you want is going to be a Short jump (less than 128 (80h) bytes, then the opcode is one byte long (74h for a JZ). If >80h bytes then it's a 2 byte Near jump opcode (0F84h for JZ). So, that's at least one step that can be hard coded.

The other bit is the displacement value of the jump. For a Short jump it's 1 byte long, i.e. 00 to 7F. For a Near jump it can be up to 4 bytes long. If you set a label where you want to jump to, i.e a MessageBox, then you can use OFFSET again to calculate the displacement of the jump.

I wrote a little proggy with source that I'll attach that shows this for both Short and Near jumps.


The idea is sort of:

-------------------------------------------------------------------

mov eax, offset SMC line
mov ebx, offset Line to jump to

;#bytes between start of SMC line and where to jump to
sub ebx,eax

;mov 74h Short jump opcode to first byte of SMC line
mov byte ptr[eax],74h

;compensate 2 bytes for a short jump since jump actually takes place at the END of the line
sub ebx,2

;set pointer to where displacement byte goes
inc eax

;mov displacement bytes into position
mov [eax],ebx

;SMC JZ line now fully produced

------------------------------------------------------------------

And no, I wasn't planning on using this in the "enhanced" version

Cheers,
Kayaker

Clandestiny
June 1st, 2001, 19:51
Quote:
Kayaker (05-31-2001 00:48):
In the 2nd step however you still have to manually calculate the opcode and displacement bytes and MOV them as a hex value. I wanted to see if this could also be done entirely as ASM coding and came up with this.


Hi Kayaker,

That was a very clever idea with the JMP and thanks for going to the trouble to write me up an example In your example you were writing into an empty section of code and it worked perfectly, but when overwriting some existing code I think there could still be some problems. I think you'd still have to manually calculate opcode lengths for both the inserted instructions and the overwritten instructions to make sure they both fall on the same instruction boundary. Else the remainder of the code will likely be transformed into garbage (as I've had the pleasure to witness quite a few times now Likewise, I've seen my valuable data in one of the registers modified more than once by garbage instructions. It seems one has to be VERY careful about which registers are modified, keeping the meaningful values in the calcuation separate from the bogus ones in the routine. Inserting an SMC instruction or 2 seems not to be too hard, but have you tried a whole block of em? And IMO, you need a whole block of interlaced SMC / real instructions for some meaningful obsfucation Man, I'll tell you right now its a painful coding job and I haven't met with much success... err, I mean it crashes every time I try to run it with more than just a few SMCed lines... I guess I just don't fully grasp the technique yet... And its shattering my delusions of grandeur for pages and pages of SMC obsfucating my "enhanced" protection ;-) I'll be lucky to get a decent obsfucation of 5 lines the way its going...LOL

Cya,
Clandestiny

Kayaker
June 2nd, 2001, 18:36
Hi Clandestiny,

Quiet in here isn't it? Just the sound of our own voices echoing off the walls...

You're right, that was *very* optimized and basic SMC. I had used 6 nops as the 'reserved' bytes where the new SMC generated jump was to be created just for clarity. If I had used real code totalling 6 bytes, then in the case of a Short jump, which is only 2 bytes long, there would be 4 bytes left over which as you say, could translate into bogus code which would screw up the rest of the code below. It didn't really matter anyway because the Short jump jumped over any bad code directly to the proper address in any case.

I know what you mean by generating a block of SMC is more challenging. And confusing. I was thinking you could always pad extra bytes with nops or some other innocuous series of bytes to make it easier. Say you wanted to create an 8 byte code sequence. You could have a bogus 5 byte Call statement, say to GetTickCount or some other API which doesn't push anything onto the stack, or maybe to a fake call somewhere in your code. Then pretend to mov the return value to some garbage variable, producing another 5 bytes to play with

E82C5AB7BF CALL KERNEL32!GetTickCount
A334124000 MOV [00401234],EAX

This now looks like valid confuse-a-cracker code Then your SMC generating code can mov 2 DWORDS worth of bytes giving you the new 8 byte code sequence, and a WORD mov of 9090 will fix up the extra 2 bytes so it doesn't crash. Or you could use inc eax, dec eax or something like that.

Again though, even this is very simplistic. You probably don't want all these extra nops kicking around but would prefer the SMC and original code to "mesh".

I suppose you could even have "layers" of SMC - a mov dword statement *creating* another mov dword statement which produces the real SMC code you want. Yikes, the brain reels at the House of Mirrors concept.

Hey Clandestiny, I know you're a talented graphic artist, I've seen some of your work. I know you like to take a word or idea and conceptualize it into an image. Think you could do that with the programming concept of SMC? Y'know, the Board *could* use a fancy graphic to jazz it up a bit... ^_^

...seed planted...

...water...

...feed...

...weed...

...Blossom!

Cheers,
Kayaker

smokin'
June 13th, 2001, 16:53
I can't get the link to harlequin home page to work. Does anyone know if he moved or what?

Sorry all, couldn't get it to work for 2days but it's working again to night!

Cold Coder
June 14th, 2001, 04:50
Hi all

http://www.angelcities.com/members/harlequin/
http://www.Harlequin00.cjb.net
http://htasks.cjb.net/fx23ht.zip

all work for me
--------------
This how i did the SMC for fx23ht.exe
; at about 004010CA and WellDone at NA(not telling hehehe)
mov eax, Modif
mov dword ptr [eax], 0Fh*1h + 84h*100h + (WellDone-Modif-6)*10000h
Modif EQU $
;C7h, 00h_________, 0Fh, 84h, 00h, 00h
mov dword ptr [eax], 0000840Fh ; give us 6 bytes(for jz xxxx0000)

2 other things
here some thing cool
:00401142 80F3DC xor bl, DC ; aka 'Ü' aka ALT 666(you bad Harlequins)

and fx23ht.exe has a cool bug at about WellDone by sending hInstance and not hWnd to MessageBox get it into a loop(well for me it dos)

Cheers,
Cold Coder

Cold Coder
June 14th, 2001, 06:11
Hi smokin,
one more thing harlequin is away right now(i think he will b back soon) so if it go down 100% then it down for now.

cya,
Cold Coder

Kayaker
June 15th, 2001, 00:30
Hi Cold Coder,

Glad to see someone else working on this. You're right, hInstance is pushed as the 1st param in the MessageBox calls rather that hWnd, which is what it's supposed to be (or NULL) according to the API reference, even though it doesn't seem to make a great deal of difference. I hadn't noticed this error, just recognized 400000 in Harl's original file as an Instance handle returned from the GetModuleHandleA call, and used hInstance in my code. Unfortunately this doesn't get rid of the infernal message loop when you get the correct 'serial', at least for me.

If I use hInstance or NULL as the 1st param of the MessageBox call, I get multiple message boxes and a flickering of the dialog window. If I use hWnd, I get multiple message boxes, but the flickering stops and it seems to exit from the loop a bit more gracefully.

It still seems to have to do with wm_command being processed too many times. If you set a bp on the code line .ELSEIF uMsg==WM_COMMAND (401044 in the original file), and step over the good MessageBox when it's called, you immediately break at that wm_command line again, even before the MessageBox call finishes and displays its message. So of course the GetWindowTextA / cmp dword ptr [variable], 73704F4Fh / MessageBox routine gets called *again*, which is totally redundant.

wm_command is also sent when a control sends a notification message to its parent window. I used Winsight to monitor the windows messages in both the main dialog and the edit control when something is typed into the edit box. After the 1st wm_command is processed, it seems there are still some messages from the edit box sitting in the message queue , one (or more) of them which cause further wm_command messages to be sent to the main window, causing the bug.

I haven't tracked down the exact source of the multiple wm_command messages. I think this is just a one-off problem with using wm_command as a tricky way to monitor when there's a change in the edit box. Maybe using a less generic wm_ message such as WM_GETTEXT or WM_GETDLGCODE (both of which are also sent by the edit box) might work better.

Cheers,
Kayaker

Cold Coder
June 15th, 2001, 02:50
Hi Kayaker,

> Glad to see someone else working on this.
I have bin here/working(i think some other ppl have too "read 435 times" from the start project.(i just think my post sucks so i do not post much)

This what i did i used the edit box hWnd as it save any way(bing the way code work i have to save the main one). So this may have stop all message from the Edit box.

Cheers,
Cold Coder

Kayaker
June 16th, 2001, 22:30
Hi All,

I came up with a solution to the errant message loop problem in Harlequin's original file that caused that flickering/mulitiple message boxes. The wm_command processing loop needed another test to isolate when a single change was occuring in the edit box before continuing on to the GetWindowTextA call.

If you use Winsight (or Ispy) to monitor the wm_command windows messages being sent to the dialog box when you type a character into the edit box, you also get the values of wParam and lParam. For each keystroke entered there are 2 wm_command (111h) messages sent from the child window (the edit box) to the parent window (the dialog box):

"Harlequin 7" WM_0x111 Sent wp=0400006B lp=00000524
"Harlequin 7" WM_0x111 Sent wp=0300006B lp=00000524

lParam just gives the hWnd of the child window
The low-order word of wParam is the Control ID = 006B = the edit box ID
The high-order word of wParam is the Notification Code

The Notification Code is the interesting one. There are 2 of them, 0400 and 0300. Doing a search for them I found they corresponded to EN_UPDATE and EN_CHANGE.

The EN_UPDATE notification message is sent when an edit control is about to display altered text. This notification message is sent after the control has formatted the text, but before it displays the text. This makes it possible to resize the edit control window, if necessary. The parent window of the edit control receives this notification message through the WM_COMMAND message.

The EN_CHANGE notification message is sent when the user has taken an action that may have altered text in an edit control. Unlike the EN_UPDATE notification message, this notification message is sent after Windows updates the screen. The parent window of the edit control receives this notification message through the WM_COMMAND message.


So now either one of these messages can be used to make sure the GetWindowTextA routine is called only once for each keystroke:
------------------------------------------
.ELSEIF uMsg==WM_COMMAND
jmp wmcommand
.
.

wmcommand:
mov eax,wParam ; check low-order word of wParam
.IF ax==IDC_BUTTON ; button pushed?
invoke FakeCheck,hWnd

.ELSEIF ax==IDC_EDIT ; something entered into edit box (ID=6B)?
shr eax,16 ; shr to check high-order word of wParam
.if ax==EN_CHANGE ; equal to 0300?

invoke GetWindowTextA, hEditReg, ADDR strReg, 20h
cmp dword ptr [strReg], 73704F4Fh
.
.
------------------------------------------------

I also set a BMSG hwnd WM_COMMAND breakpoint in SoftIce to monitor things and found something unusual. SI lists the Notification Code in lParam instead of wParam. This must just be an internal syntax because according to all API documentation, Numega's got it wrong!

Break due to BMSG 0B34 WM_COMMAND
hWnd=0B34 wParam=006B lParam=03000B3C msg=0111 WM_COMMAND

Just thought this might be interesting. At least now I can sleep better

Kayaker