Log in

View Full Version : dongle app written in dos


ksbrace
January 24th, 2006, 17:27
Ok,
I'm playing around with an old app that a bowling alley near my house uses all of the time. It appears to have been written in DOS and it crashes W32DASM everytime I attempt to load it. It uses ntvdm.exe, after looking this up, it is a 16bit dos emulator...correct? I load it in Olly and I see this:
7C90EB94 C3 RETN
7C90EB95 8DA424 00000000 LEA ESP,DWORD PTR SS:[ESP]
7C90EB9C 8D6424 00 LEA ESP,DWORD PTR SS:[ESP]
7C90EBA0 90 NOP
7C90EBA1 90 NOP

Searched this forum and found something relative to this here:http://www.woodmann.com/forum/showthread.php?t=7411&highlight=file+analysis
on post #2. So, based on that something is happening before original entry point.

I also found IsDebuggerPresent when I ctrl-N.

Maybe this is above my head, but I thought maybe I could ask for a few pointers and/or things to try out. IMHO, I find it highly doubtful that this is that secure.....but I could be wrong. Thanks in advance

SiGiNT
January 24th, 2006, 17:55
ksbrace,

Unless olly is disassembling incorrectly, this is not a 16 bit app, it uses extended registers, ESP vs: SP, EAX vs: AX - a good way to really check this out is to find a copy of IDA 4.3 - the free version or if you are fortunate enough a later versions, (it's up to 4.8xx, with 5.0 coming soon), it should tell you if it really is a 16 bit NE app. Also IsDebuggerPresent wouldn't be found in old dos apps.

SiGiNT

ksbrace
January 24th, 2006, 17:59
Sigint33,
I get a message when I load it in Olly saying: Not a valid PE file
file 'target' is probably not a 32-bit Portable Executable. Try to load it anyway?

I chose yes. I will look for a copy of IDA and try using that.

ksbrace
January 24th, 2006, 18:11
Ok, found 4.3..didn't search too hard for any later version.
At the top it says:
File Name: target
Format: MS-DOS executable
then at seg000, it says:
segment byte public 'CODE' use16.

SiGiNT
January 24th, 2006, 18:17
Don't take my word as gospel, yes ntdvm.exe is NT Dos Virtual Machine - but in googling around I found that its also employed for Win98 compatability - if it is a 16 bit dos app. then you may have to resort to using Borland's Turbo Debugger - I think if you search this forum you may find some info on it - I have a 16 bit app that I've fixed everything except the initial nag - (from a dead listing), and it behaves similarly to what you describe - if you get Turbo Debugger running on XP SP2 let me know how, it always locks up on me - but I really didn't spend more than a couple of minutes playing with it.

SiGiNT

esther
January 24th, 2006, 23:25
If I'm not wrong Turbo Debugger doesn't works in winxp.You can try this debugger super tracer tr252.zip.

SiGiNT
January 24th, 2006, 23:57
I'll give it a try!

Thanx esther.

LLXX
January 25th, 2006, 01:30
Quote:
[Originally Posted by ksbrace]I load it in Olly and I see this
That's somewhere in the kernel. What you need to determine is whether Olly is actually loaded the ntvdm.exe or your target. This can be done by changing the options so that Olly breaks at the entrypoint.

The best way to determine what file format it is written in is to open it in a text editor like Notepad and examine the header portion. If the prominent letters "PE" appear in the middle of some whitespace then it's a standard Win32 PE, if it's NE then it's Win16, and if there's nothing but repetitive-looking entries it would be a standard DOS MZ.

ksbrace
January 25th, 2006, 10:51
LLXX,
Olly loaded ntvdm.exe. When I loaded the target.exe into Notepad, I found this:
Borland C++ - Copyright. When I start the app, I get the following message(Prior to the 'no dongle present' msg):
Title: 16 bit MS-DOS Subsystem
path/target.exe
RNBOVDD.DLL. An installable Virtual Device Driver faild DLL initialization. Choose 'Close to terminate the application.

esther
January 25th, 2006, 11:28
*Sigint33,
I get a message when I load it in Olly saying: Not a valid PE file
file 'target' is probably not a 32-bit Portable Executable. Try to load it anyway?

Well 16bits programs (windows3.1 )doesn't mean its a dos one since you can load it in ollydbg and you found isdebuggerpresent api which means its a windows program

ksbrace
January 25th, 2006, 11:31
ok, after another look, I found the isdebuggerpresent inside the ntvdm.exe and not the target.exe.

LLXX
January 25th, 2006, 23:45
Quote:
[Originally Posted by ksbrace]When I loaded the target.exe into Notepad, I found this:
Borland C++ - Copyright.
That just indicates that it was compiled with Borland's C++ compiler... and you're looking too far into the file. Turn on the word wrap and scroll up until you see the "MZ" as the first two characters.

If you can find "This program cannot be run in DOS mode" and then the letters "PE" after some miscellaneous characters, it's a PE.

A Win3.1 file will have "This program requires Microsoft Windows" and then "NE" immediately before some "Ç" characters.

A standard DOS MZ will have none of the above characteristics.

Based on what you've posted so far, my assumption is that you have a standard MZ file.

hadicol
January 26th, 2006, 02:25
i have tried debugging dos programs with olly on XP. i gave up because i can never seem to get out of the ntvdm emulator and into the program! now that i think of it, you can probably never enter the program assembler.

however you can use the good ol' "debug" program (yes, debug is the name of the program). it's command line, ugly, it works, and even though its 16bit only it still comes with windows for some reason... type ? for help. But turbo debugger is alot easier, runs fine for me (XP SP2), free for download. HIEW can disassemble 16bit too. these work because they are also being run under ntvdm!

so basically, ya it's a 16-bit program if ntvdm is running it. so use outdated tools. 32bit tools will not process it correctly. If it is an old 16-bit Windows program the "Windows on Windows" emulator wowexec.exe will also be in the process list as well as ntvdm.exe if theres no wowexec it is DOS.

naides
January 26th, 2006, 02:38
In DS 3.2 and I'm almost sure DS3.1 \SoftIce Folder there is a subfolder called util16.

In there are two files, symbol loaders, that need to be invoked from a DOS window:
DLDR.exe for MZ format DOS 16 bit applications
and
WLDR.exe for NE format Windows 16 bit applications


Sice pops up and you are at the entry point of your prehistoric code.
Sice fucks up/locks up even more frequent than the usual while tracing those 16 bit creatures, but a difference from old Borland Turbo debuggers an other outdated toys, Sice 16 bit debugger runs in a pure 32 bit OS (WinXP) and CPU (Pentium 4)

ksbrace
January 27th, 2006, 17:05
I could use some help/guidance on the following:
I start the target and immediately hit ctrl-D. I then begin to F10 and I get to a line that looks like this:
Code:

FE2E:377C CALL 5001


That line causes the 'Target security missing' msg.

My question: what is the FE2E?

When I look with w32dasm, I don't see anything close to FE2E.

Also, I don't seem to be utilizing the dldr.exe and wldr.exe files. Based on the info that I have looked, I want to use the dldr.exe.

naides
January 27th, 2006, 18:07
KS:
Answer #1:
A crash lesson in memory addressing for 16 bit code.
In those times, the biggest number that a register could hold was a 'word' hex FFFF or dec 65535.
Programs grew a lot bigger than that, so, to be able to define an address in the code, or in the data, it was necessary to use a more than one register.
That scheme of addressing was called segmented memory or Segment:Offset.

So when you are referring to a given line of code, the address is a composite of the CS (Code Segment) and an offset which measures the distance from the the beging of the CS.

For instance
FE2E:377C

The segment FE2E defines a area in memory taht is 65535 bytes long,
located at FE2E0 bytes from 0. The segment goes from FE2E:0000 to FE2E:FFFF
FE2E:377C refers to the instruction located 377C bytes above FE2E:0000, which is FE2E0 bytes from memory 0000:0000

When you are dealing with data, the base address (Segment Address) is contained on the register DS (Data Segment) or the Register ES (Extra segment.
To make things worse this segmented concept of memory was designed to address only 1 megabyte of memory (hex FFFFF )

For instance the byte pointed by the segment: Offset address 0000:0011 is loacated at 11 bytes from 00000, could also be pointed by the Address 0001:0001, located 1 byte above 00010. Segmented addressing has a lot of overlap
The difference between segment 0000 and segment 0001 is only hex 10 or dec 16 bytes (A 'paragraph').


Fucking confusing.

With the advent of 32 bit CPU and OS, came the flat memory model, in which a memory address fits in a 32 bit register with a max value of FFFFFFFF or 4 gigabytes. You can refer to any place in memory using a single register. Data Segment (DS) Extra Segment (ES)Code Segment (CS) FS and GS acquired a whole new meaning and are for the most part used just as shortcuts (Selectors)to get to a specific areas in a simple (Flat) memory space address, and also to facilitate the virtual and protected memory architecture of the Windows OS.


#2
in 16 bit apps, the CS (that FE2E: part) is assigned and calculated dynamically, when tha app is loaded. A disassembly will not contain that CS address, only the offset is realiable.
Also, the FE2E: address you are seing is in the high memory area which belong to the (DOS)Operating system. The code that you are tracing, is not in you APP but in DOS.
You need to use the DLDR.exe to load your app and to land inside your app code.

I assume you are using Sice right now, right?

You need to open a DOS window
(by using the run-> cmd option at your start menu.)


Navigate, using DOS commands to your \util16 folder

In DOS window, invoke DLDR.exe followed by the path and name of the app you want to debug (All by sheer typing, welcome to DOS)

like at the prompt c:\Program Files\Compuware\Driverstudio\SoftIce\Util16>

Type:

DLDR c:\some folder\myappfolder\target.exe

Sice will popup at the entry point of your app code.
You can check and see that the Disasm and the Sice code coincide.

ksbrace
January 31st, 2006, 10:59
Ok, I found a couple of places that may/may not be of interest in the app. My problem is this....in SI, I see 0DDB:00B3 as a line where I would like to modify. In W32DASM, the same line looks like: 0001.00B3. In HIEW, I can't find the line. I peformed searches looking for both (0DDB and 0001). Any help on this would be great! Thanks in advance.

Code:

Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.003F(C)
|
:0001.0037 F2 repnz
:0001.0038 AE scasb
:0001.0039 E343 jcxz 007E
:0001.003B 43 inc bx

:0001.003C 2638 WORD 3826
:0001.003E 0575 WORD 7505
:0001.0040 F680 WORD 80F6
:0001.0042 CD80 WORD 80CD
:0001.0044 F7D9 WORD D9F7
:0001.0046 890E WORD 0E89
:0001.0048 7400 WORD 0074
:0001.004A B902 WORD 02B9
:0001.004C 00D3 WORD D300
:0001.004E E383 WORD 83E3
:0001.0050 C310 WORD 10C3
:0001.0052 83E3 WORD E383
:0001.0054 F089 WORD 89F0
:0001.0056 1E78 WORD 781E
:0001.0058 008C WORD 8C00
:0001.005A D22B WORD 2BD2
:0001.005C EABF WORD BFEA
:0001.005E F23D WORD 3DF2
:0001.0060 8EC7 WORD C78E
:0001.0062 268B WORD 8B26
:0001.0064 3E86 WORD 863E
:0001.0066 0B81 WORD 810B
:0001.0068 FF00 WORD 00FF
:0001.006A 0273 WORD 7302
:0001.006C 08BF WORD BF08
:0001.006E 0002 WORD 0200
:0001.0070 2689 WORD 8926
:0001.0072 3E86 WORD 863E

:0001.0074 0BB104D3 or si, [bx+di+D304]
:0001.0078 EF out dx, ax
:0001.0079 47 inc di
:0001.007A 3BEF cmp bp, di
:0001.007C 7305 jnb 0083
:0001.007E 90 nop
:0001.007F 0E push cs
:0001.0080 E80058 call 5883

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.007C(C)
|
:0001.0083 8BDF mov bx, di
:0001.0085 03DA add bx, dx
:0001.0087 891E8400 mov [0084], bx
:0001.008B 891E8800 mov [0088], bx
:0001.008F A17A00 mov ax, word ptr [007A]
:0001.0092 2BD8 sub bx, ax
:0001.0094 8EC0 mov es, ax
:0001.0096 B44A mov ah, 4A
:0001.0098 57 push di
:0001.0099 CD21 int 21
:0001.009B 5F pop di
:0001.009C D3E7 shl di, cl
:0001.009E FA cli
:0001.009F 8ED2 mov ss, dx
:0001.00A1 8BE7 mov sp, di
:0001.00A3 FB sti
:0001.00A4 B8F23D mov ax, 3DF2
:0001.00A7 8EC0 mov es, ax
:0001.00A9 26893E860B mov es:[0B86], di
:0001.00AE 833EF40514 cmp word ptr [05F4], 0014
:0001.00B3 7649 jbe 00FE
:0001.00B5 803E7C0003 cmp byte ptr [007C], 03
:0001.00BA 7242 jb 00FE
:0001.00BC 7707 ja 00C5
:0001.00BE 803E7D001E cmp byte ptr [007D], 1E
:0001.00C3 7239 jb 00FE

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.00BC(C)
|
:0001.00C5 B80158 mov ax, 5801
:0001.00C8 BB0200 mov bx, 0002
:0001.00CB CD21 int 21
:0001.00CD 722A jb 00F9
:0001.00CF B467 mov ah, 67
:0001.00D1 8B1EF405 mov bx, [05F4]
:0001.00D5 CD21 int 21
:0001.00D7 7220 jb 00F9
:0001.00D9 B448 mov ah, 48
:0001.00DB BB0100 mov bx, 0001
:0001.00DE CD21 int 21
:0001.00E0 7217 jb 00F9
:0001.00E2 40 inc ax
:0001.00E3 A38C00 mov word ptr [008C], ax
:0001.00E6 48 dec ax

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.FFEB(U), :0001.FFF3(U)
|
:0001.00E7 8EC0 mov es, ax
:0001.00E9 B449 mov ah, 49
:0001.00EB CD21 int 21
:0001.00ED 720A jb 00F9
:0001.00EF B80158 mov ax, 5801
:0001.00F2 BB0000 mov bx, 0000
:0001.00F5 CD21 int 21
:0001.00F7 7305 jnb 00FE

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.00CD(C), :0001.00D7(C), :0001.00E0(C), :0001.00ED(C)
|
:0001.00F9 90 nop
:0001.00FA 0E push cs
:0001.00FB E88557 call 5883

Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.00B3(C), :0001.00BA(C), :0001.00C3(C), :0001.00F7(C)

|
:0001.00FE 33ED xor bp, bp
:0001.0100 55 push bp
:0001.0101 90 nop
:0001.0102 0E push cs
:0001.0103 E88069 call 6A86
:0001.0106 58 pop ax
:0001.0107 2E8E066002 mov es, cs:[0260]
:0001.010C BEA80E mov si, 0EA8
:0001.010F BFEA0E mov di, 0EEA
:0001.0112 E8C600 call 01DB
:0001.0115 FF367200 push word ptr [0072]
:0001.0119 FF367000 push word ptr [0070]
:0001.011D FF366E00 push word ptr [006E]
:0001.0121 FF366C00 push word ptr [006C]
:0001.0125 FF366A00 push word ptr [006A]
:0001.0129 9AE390800A call 0A80:90E3<-- brings up 'Security missing' msg
:0001.012E 50 push ax
:0001.012F 90 nop
:0001.0130 0E push cs
:0001.0131 E8E856 call 581C

* Referenced by a CALL at Address:
|:0001.57E7
|
:0001.0134 2E8E066002 mov es, cs:[0260]
:0001.0139 56 push si
:0001.013A 57 push di
:0001.013B BEEA0E mov si, 0EEA
:0001.013E BF020F mov di, 0F02
:0001.0141 E8DB00 call 021F
:0001.0144 5F pop di
:0001.0145 5E pop si
:0001.0146 CB retf


So, I thought that these references may be the key to circumventing the security based on the call that produces the error msg....or not:
:0001.00B3(C), :0001.00BA(C), :0001.00C3(C), :0001.00F7(C)

Does it seem like I'm on the right track or not?

naides
January 31st, 2006, 13:54
Hi KS.
You are certainly making progress.
1. You can test if changing those jmps indeed bypass the protection by changing them in Sice before they execute:

Type in Sice:

A (for Assemble) 0DDB:0083

then type the new instruction you want in its place

jmps 00C5 (jmps means jmp short)

To find your code in HIEW for permanent patching

Do not relay on the code addresses. Use the search F7 function and enter a pattern of 10 to 14 bytes around the instruction you want to change
Code:

:0001.00A9 26893E860B mov es:[0B86], di
:0001.00AE 833EF40514 cmp word ptr [05F4], 0014
:0001.00B3 7649 jbe 00FE

strike <F7>: 26 89 3E 86 08 83 3E F4 and you should land nearby the code. Then patch away

ksbrace
January 31st, 2006, 15:11
Can you tell me if the hiew demo has the search disabled? I have searched for strings that I can see in the window and it says "Target not found".

On another note, I type in:
A 0DDB:00B3 and hit enter, sice asks me for the instructions and I'm not sure what I want to type in: For instance, if 00B3 is jbe 00FE and it doesn't jump, I was going to make it a ja 00FE so it should jump. I tried typing in: 77 00FE and 0F87 00FE but sice is not happy with those commands. Thanks,

SiGiNT
January 31st, 2006, 16:02
If it works like Olly, type in ja 00FE

SiGiNT

ksbrace
January 31st, 2006, 16:47
SigiNT,
Thanks for the tip, works like Olly! Unfortunately, the changes I made( :0001.00B3(C), :0001.00BA(C), :0001.00C3(C), :0001.00F7(C) ) relating to 0001.0129 would eventually send me to 00F9 which is 'abnormal program termination' msg. I tried to work around that, but it sent me to 0001.0099 which is also the same as 0129- 'Security missing' msg.

So, back to the drawing board.

ksbrace
February 1st, 2006, 12:15
FYI,
HIEWDemo has the search disabled...or at least it doesn't search. F7 will bring up the search field, but it never finds anything. The full version, however, does search correctly.

Here's a thought, but it seems like cheating.... I have access to the dongle. So, I thought about comparing the code with the dongle to the code without the dongle and see where it goes.

naides
February 1st, 2006, 15:09
In War, every thing goes

If you can find this tut

Cracking 99% of all Time Trials - Written by Mushy

It is somewhere in Krobar's collection

It will give you inspiration on how to save the traces with and without dongle and zero in the critical decision points

ksbrace
February 1st, 2006, 15:28
Naides,
Found the tut with little trouble. Now that seems like a great plan of attack. Question removed because JMI thought I should have just asked google instead of Naides

Thanks,

JMI
February 1st, 2006, 15:55
ksbrace:

Do you do ANY of your own basic research??? Put "saving log window ollydbg" (without the quotes) in your favorite search engine and read for yourself what you want to know about how to use the tools of the trade.

Here's another hint for the lazy. Search for "What's new in OllyDbg" (without the quotes) and actually READ IT!

Regards,

SiGiNT
February 1st, 2006, 18:46
Quote:
[Originally Posted by ksbrace]FYI,
Here's a thought, but it seems like cheating.... I have access to the dongle. So, I thought about comparing the code with the dongle to the code without the dongle and see where it goes.


If you are truly industrious and a bit of an entrepeneur in your work then you may want to check out a thread from about 2 years ago on "how to build a dongle emulator" written by a kid but quite amazing work, but worth it in my view. Don't search the string quoted above but "dongle+building" would be my guess as a start.

SiGiNT

ksbrace
February 2nd, 2006, 16:55
Ok, I have tried to log the 16 bit app in Sice, but with no successs. the regular Symbol Loader wants a 32 bit app. Inside Sice there is a directory called util16 and inside that there is WDLR.exe which is supposedly a symbol loader. When I bring up the help for wdlr, it states to browse for my exe and hit the load button, the load button is never enabled and I get a message in the bottom of the window "SoftICE is not loaded". That message is not correct, because Sice is loaded. I can ctrl-d and it pops up. I have also tried going to the start menu and Starting Softice just prior to bringing up the wdlr.exe and it still says it's not loaded. I did see some threads referring to the 'cracking trials 99% of time by mushy', but they are using older versions of everything as well as a thread relating to icedump. So, does anyone have experience in logging the 16 bit app in sice?

I went and grabbed the dongle from the bowling alley. It's a sentinel Scribe parallel dongle.

SiGiNT
February 2nd, 2006, 17:39
Interesting, my guess would have been Sentinel Rainbow - because of the dll you mentioned - is it beige in color or Teal Green, not that it makes much difference unless you are writing an emulator, the Teal ones there are no standard emulators for, the were created for custom applications.

SiGiNT

ksbrace
February 2nd, 2006, 18:00
SiGiNT,
It is beige in color.....And it says Rainbow Technologies across the top and Sentinel Scribe on the bottom. I grabbed the sentinel medic from their website and it recognized it as a Scribe.

naides
February 2nd, 2006, 18:20
Quote:
[Originally Posted by ksbrace]Ok, I have tried to log the 16 bit app in Sice, but with no successs. the regular Symbol Loader wants a 32 bit app.

I went and grabbed the dongle from the bowling alley. It's a sentinel Scribe parallel dongle.



The loader for DOS apps is DLDR.exe
not symbol loader, not WDLR.exe
When you use DLDR, Sice breaks at the entry point

But now that you mention it, you NEED the Loader32 to be able to save the run-trace. . .

Oh, fuck.

UNLESS you find a way to make Sice save the log without the Symbol Loader, the strategy depicted by Mushy will not fly verbatim, but the CONCEPT is still valid.

Well, you always have paper and pencil

One more thing. In windows API calls are the way of life. DOS predates that. The Gross equivalent to API calls are interrupts, typically int 21.

I may be wrong but in Linux the gross equivalents are 'System Calls'

SOOOO.
Do not expect to find ANY API calls, you can search for the most typical DOS and BIOS interrupts in the net, so you know what is going on

SiGiNT
February 2nd, 2006, 18:28
ALT - PrintScreen also works.

SiGiNT

Just a thought but would DLDR.EXE >PRN work?

ksbrace
February 3rd, 2006, 17:31
Ok, I stepped through both machines at the same time to try and figure out where the paths are different. At this point I need to turn to someone for some advice. Both take the same path up until this loop:
Code:

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.0359(C), :0001.0362(C)
|
:0001.034B F2 repnz
:0001.034C AE scasb
:0001.034D E31F jcxz 036E
:0001.034F 263A05 cmp al , es:[di]
:0001.0352 741A je 036E
:0001.0354 26813D3837 cmp word ptr es:[di], 3738
:0001.0359 75F0 jne 034B
:0001.035B 268B5502 mov dx, es:[di+02]
:0001.035F 80FA3D cmp dl, 3D
:0001.0362 75E7 jne 034B
:0001.0364 43 inc bx
:0001.0365 80E6DF and dh, DF
:0001.0368 80FE59 cmp dh, 59
:0001.036B 7501 jne 036E
:0001.036D 43 inc bx

at .0352 the good one, doesn't jump until much later than the bad one does. I'm not sure what I should be looking for to compare the two. Thanks in advance.

SiGiNT
February 3rd, 2006, 18:49
Well, I haven't been following this very closely, but it looks to me like you've found the dongle reading routine - if they both jump at .0352, then my guess is your "good guy" "bad guy" jump is somewhere after that jump.

SiGiNT

LLXX
February 4th, 2006, 02:39
Quote:
[Originally Posted by ksbrace]Ok, I stepped through both machines at the same time to try and figure out where the paths are different. At this point I need to turn to someone for some advice. Both take the same path up until this loop:
Code:

:0001.034B F2 repnz
:0001.034C AE scasb
:0001.034D E31F jcxz 036E
:0001.034F 263A05 cmp al , es:[di]
:0001.0352 741A je 036E
:0001.0354 26813D3837 cmp word ptr es:[di], 3738
:0001.0359 75F0 jne 034B
:0001.035B 268B5502 mov dx, es:[di+02]
:0001.035F 80FA3D cmp dl, 3D
:0001.0362 75E7 jne 034B
:0001.0364 43 inc bx
:0001.0365 80E6DF and dh, DF
:0001.0368 80FE59 cmp dh, 59
:0001.036B 7501 jne 036E
:0001.036D 43 inc bx
at .0352 the good one, doesn't jump until much later than the bad one does. I'm not sure what I should be looking for to compare the two. Thanks in advance.
You're looking in the wrong place. That would be the environment block parser of Borland's Turbo-C and C++ startup code

The annotated source I have of the startup module (v.2.01) matches almost exactly (it's slightly different because of the different version...):
Code:
les di [.env] ; point to env block
mov ax di
mov bx ax
mov cx h7FFF ; look thru max 32767 bytes
:Check_87
es
cmp w[di] '78' ; we have envar "87"?
jnz .No_87
es
mov dx [di+2]
cmp dl h3D ; '=' - "87=" ?
jne .No_87
and dh hDF ; conv upcase
inc w[.use_8087]
cmp dh 'Y' ; "87=Y" ?
jne .No_87 ; no...
inc w[.use_8087]
:No_87
repnz scasb
jcxz .No_more_env ; dont try to go past 32k of env
inc bx ; one more env var to check...
es
cmp [di] al ; end?
jnz .Check_87 ; no, keep going...
If you're interested in the rest of the startup code, Google "c0.asm" (w/o the quotes) and it'll be the first link.

The *real* start of your program's code can be found by locating the call to the main() function, which looks like this:
Code:
push [.env]
push [.argv]
push [.argc]
call .main
Those three pushes are distinctive and easy to find. Look for an Int 1A and it'll be a few instructions down. Start your analysis at the main() function.

ksbrace
February 4th, 2006, 12:18
As I step through both machines, I come to .5F89. Here, I'm seeing some bizarre behaviors and I'm not sure if this is a place that I care about or not.
On the Good machine, sometimes it jumps and sometimes it doesn't. Same with the Bad machine.
I ran it about 6 times through this area to try and compare because the first time through they were different:
Good Guy
5f89 jumps to 5f99
5fa0 jumps to 5f84
5f89 no jump
5f97 jumps to 5fa2
returns to 0214
---
Good Guy:
5f89 no jump
5f97 jumps to 5fa2
returns to 0214
---

Bad Guy:
5f89 jumps to 5f99
5fa0 jumps to 5f84
5f89 jumps to 5f99
5fa0 jumps to 5f84
5f89 jumps to 5f99
5fa0 jumps to 5f84
5f89 no jump
5f97 jumps to 5fa2
returns to 0214
---
Bad Guy:
5f89 no jump
5f97 jumps to 5fa2
returns to 0214

Am I wasting mine/your time looking in this area? Thanks in advance!


[/CODE]
:0001.5F70 C3 ret

:0001.5F71 55 push bp
:0001.5F72 8BEC mov bp, sp
:0001.5F74 83EC02 sub sp, 0002
:0001.5F77 56 push si
:0001.5F78 57 push di
:0001.5F79 1E push ds
:0001.5F7A B8F23D mov ax, 3DF2
:0001.5F7D 8ED8 mov ds, ax
:0001.5F7F C746FE0000 mov word ptr [bp-02], 0000

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.5FA0(C)
|
:0001.5F84 E8C5FF call 5F4C
:0001.5F87 A801 test al, 01
:0001.5F89 750E jne 5F99
:0001.5F8B C706AC0C0000 mov word ptr [0CAC], 0000
:0001.5F91 C706AA0CA904 mov word ptr [0CAA], 04A9
:0001.5F97 EB09 jmp 5FA2



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.5F89(C)
|
:0001.5F99 FF46FE inc word ptr [bp-02]
:0001.5F9C 837EFE64 cmp word ptr [bp-02], 0064
:0001.5FA0 7CE2 jl 5F84

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.5F97(U)
|
:0001.5FA2 1F pop ds
:0001.5FA3 5F pop di
:0001.5FA4 5E pop si
:0001.5FA5 8BE5 mov sp, bp
:0001.5FA7 5D pop bp
:0001.5FA8 CB retf
[/CODE]

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

LLXX,
Now, when I try to analyze the main function, by setting breakpoint at .0F3F or any of the below addresses, it never stops, Good Guy or Bad Guy.



:0001.0F3E CB retf


:0001.0F3F 55 push bp
:0001.0F40 8BEC mov bp, sp
:0001.0F42 56 push si
:0001.0F43 57 push di
:0001.0F44 8A6606 mov ah, [bp+06]
:0001.0F47 8B4E0A mov cx, [bp+0A]
:0001.0F4A 8B5608 mov dx, [bp+08]
:0001.0F4D CD1A int 1A
:0001.0F4F 92 xchg ax,dx
:0001.0F50 8BD1 mov dx, cx
:0001.0F52 5F pop di
:0001.0F53 5E pop si
:0001.0F54 5D pop bp
:0001.0F55 CB retf

LLXX
February 4th, 2006, 21:32
The 5Fxx code seems to be calling 5F4C until it either returns 0 or has been called 100 times, whichever comes first. The "success" path would set [0CAC] to 0000 and [0CAA] to 04A9 (1193? do you recognise this number?) and then return, otherwise 0CAA and 0CAC are left unchanged. Here's a diagram of the flow:
Code:
...start...
5F84 E8C5FF call 5F4C <-----------------------+
5F87 A801 test al, 01 |
5F89 750E jne 5F99 >------------------------+ |
5F8B C706AC0C0000 mov word ptr [0CAC], 0000 | |
5F91 C706AA0CA904 mov word ptr [0CAA], 04A9 | |
5F97 EB09 jmp 5FA2 >---------------------+ | |
5F99 FF46FE inc word ptr [bp-02] <-------|--+ |
5F9C 837EFE64 cmp word ptr [bp-02], 0064 | |
5FA0 7CE2 jl 5F84 >----------------------|----+
5FA2 1F pop ds <-------------------------+
...return...
You should look inside 5F4C to see if there's anything interesting there, as the above loop is rather generic and isn't something that is specifically associated with d0ngles.

You've found the wrong Int 1A - look at the code and think! Would the call to main() be located inside a function that simply interfaces to Int1A? Once again, think! What you have there is a function! See the push bp | mov bp sp ? You should know that that is the standard opening sequence of a function, and that retf ends it!

Start at the real entrypoint and follow the code flow. You should travel through the environment parser I described earlier, followed by some calculations and Int 21 calls to setup the memory, a rep stosb or rep stosw to initialise the Bullshit Segment (BSS), then a few calls, an int 1A and then the series of Pushes followed by the call to main() itself. If you can't locate those items in your program, you need to spend some more time studying the code and looking at it from a higher perspective. The fact that what you thought was the protection check was in fact the environment block parser indicates that you should definitely take some time to study more Asm and understand the functioning of the program on the large scale, not just line-by-line.

nchanta
February 5th, 2006, 23:40
If it is indeed sentinal, it may be a good idea to search for the common sentinal constant 0x07242, if you haven't already.

Oh, and read up about sentinal at woodman.com/crackz

LLXX
February 6th, 2006, 00:55
Who knows what it is... anyway I cracked his target already by forcing one and killing another conditional jump.

ksbrace
February 7th, 2006, 09:16
Here is the pm from LLXX on how the target was cracked:

Hello,

Sorry to disappoint you, but the protection was much easier than I expected. I didn't even need to use IDA, and later when I loaded it into IDA it didn't disassemble very well, maybe that is where your difficulty exists. Always try easy way first! Target_1.exe checks once and was cracked in approximately 20 seconds, Target_2.exe checked twice and took 1 minute of my time

I'll explain now how I did it. First of all, get the general feeling of the target. Load into a text editor and look around. You find "Borland" string in there, this means it was compiled with Borland's C/C++ runtime library - important information to know, so you don't spend time tracing through the startup code like you did. Run the program. Target_1.exe first, gives the message that security is missing etc. Then, just use DOS debugger DEBUG.EXE to inspect. Run it from cmd prompt like:

debug Target_1.exe

You see the "-" which is prompt of action. You can type ? and press Enter to get the list of commands. First of all, since we know that Borland startup code is linked, the task is to find where main() function is. Enter u and press Enter to see the entrypoint. You should see the "mov ah 30" "int 21" which is very typical for startup code to do, it is just checking for DOS version. I did u 10 more times, and at :0122 finds INT 1A which you said couldn't find? This means the assumption is correct, indeed we are in the startup code. U once more, and see:

Code:

0143 BE9C2E MOV SI,2E9C

0146 BFC02E MOV DI,2EC0

0149 E8D000 CALL 021C

014C FF368800 PUSH [0088]

0150 FF368600 PUSH [0086]

0154 FF368400 PUSH [0084]

0158 E8D631 CALL 3331Recognise these pushes? It is very important! This is call to main() we have found. main() is at 3331, so run till 3331 with command g 3331 (go until 3331). Now you see the Registers displayed and push bp at the location 3331, this is the start of main(). This now takes to pay more attention to the detail, start stepping through the program. Use command p to step through without entering the CALLs. After p'ing 29 times hits Welcome screen. Press any key to exit the welcome screen, and stops at the CALL 51B3. P again, the screen clears and sees CALL 19BB. P again. See the error message comes up! Press ESC to terminate for now, 19BB returns and sees the OR AX, AX stopped at. Step once, then finds "JNZ 33A0" - now think, why would conditional jump be present after check of d0ngle? 19BB returns AX = 0, so that means FAILURE, so in this case it should not be zero, we forces it to jump by places command e cs:3396 eb which inserts EB byte (JMP opcode) into the cs:3396 where JNZ originally was. Nothing will display when you run this command, but use r command to show the current state, and finds JMP 33A0 has been shown, the byte indicates has changed from 7508 to EB08. Thinks we have found the critical jump, run g command to continue with the execution. It works! Continue entering the data, etc. Now finishes "Billing Summary" screen, press ESC and it will exit back to DEBUG, shows message "Program terminated normally" and the prompt. Run command q to exit. One supplementary exercise: It contains the year 2000 bug with the entered date. Figure out how to fix that

It actually takes much less time to step through and find the jump than to describe it above... you try it yourself and see how quick it was. Now, onto Target_2.exe - unfortunately PM system won't let me send more than 3.9Kb at once, see the next message...

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

Opens the executable in the editor, look around. It is compiled with same Borland compiler, it seems. Also note the size: 326Kb. This is much larger than the other one, so have to watch out for the segmentation when inspecting the code. Run the file. See "security error" message. It seems to be the first output produced, so the security error must be closer to the start than in the other one.

Load it into debug. Again, u. You'll see almost the same sequence of instructions as in the other one, this is a good sign that the compiler is the same. Keep u, but this time sees not the INT 1A after 9 u's, but already the pushes. Perhaps this is what confused you, however you must think - it is slightly different but you see the very easy recognises

Code:

0115 FF367200 PUSH [0072]

0119 FF367000 PUSH [0070]

011D FF366E00 PUSH [006E]

0121 FF366C00 PUSH [006C]and you know that INT 1A was executed, so then where is it? You found in the disassembly that INT 1A, and I told you it was part of a function, so that function must've been called before that. Did you notice all the CALLs that took place before the PUSHs? It most likely was one of them. U again, and finds the:

Code:

0125 FF366A00 PUSH [006A]

0129 9AE390501D CALL 1D50:90E3That is definitely the main() function (it might not be at segment 1D50, but the offset 90E3 will be the same on your machine). However, notice that the call is different from the one in the other program. Also notice that this program is much larger than the other program. This is known as an intersegment or far call, i.e. the location of call is in another segment. Then, instead of g 3331 earlier, run command g 1d50:90e3 (substitute whatever segment your program is, since I don't think it's going to be 1d50 as well). Arrives the position:

Code:

AX=0100 BX=0EEA CX=0FB4 DX=0EEA SP=0FD2 BP=0FE4 SI=0EA8 DI=0EEA

DS=50C2 ES=50C2 SS=51B3 CS=1D50 IP=90E3 NV UP EI PL ZR NA PE NC

1D50:90E3 55 PUSH BPSees again that we have reached main() entrypoint.

Again 4000 byte PM limit... see part 3...

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

As with the other one, repeat p command until find something interesting. In this case, I had to do it 118 times - watch for this:

Code:

AX=6914 BX=004C CX=0000 DX=71D8 SP=0F5E BP=0FD0 SI=0EA8 DI=0EEA

DS=4640 ES=71D8 SS=51B3 CS=1D50 IP=92D9 NV UP EI PL NZ AC PO NC

1D50:92D9 9ABD43EB3B CALL 3BEB:43BDAgain, the segments will be different, but notice the CALL - the code is in segment 1d50, but it's calling far away to 3beb. When runs the command p I notice a slight pause before it returns. This is different from all the previous p's, so something interesting is happening. It might be trying to access the dongle. Pay more attention now. P two more times over the POP CX's, then notice AX = FFFF when find the instruction MOV SI, AX. P again, and find CMP AX, FFFF and then P over that, find JZ 92AC. This is important. From use of logic, think that if the CALL succeeded, it would not return FFFF (-1) which normally indicates ERROR. So, this should not jump, and it should be striked out with two NOPs. Use the command e cs:92e5 90 90 just like the previous program to strike out the JZ, and then r to see that it has been changed to NOP. Also, use u to see what the upcoming code is going to be. You'll see more far CALLs to 43bd, i.e. what seems to be the dongle code. That means that the protection check isn't over yet (if you try to run right now, only after killing the first jmp, you get "Security error #3". P over these, until you get to the MOV SI, AX followed by CMP SI, -01. Notice once again, AX is FFFF without the dongle. Following the CMP SI, -01 (-01 is equal to FFFF), at 9314, is JNZ 9329. Following the logic, if AX was not FFFF, i.e. the dongle is OK, it will jump to 9329. Instead of killing this jump with NOP, we have to force it. The command is e cs:9314 eb. Once again, r to confirm that it has changed to JMP 9329, then P over it and U to see the upcoming code. No more calls to 43bd, it seems. We can try to run it now, with g. It works (as far as I can tell...). Again, the description I wrote above makes it seem more difficult than it really is. Try it

IMHO, this prog wasn't really worth cracking for use, but as an educational experience, it's nice. Surprisingly easy to crack for a "dongle", and I haven't the dongle either. On a difficulty scale of 0 - F, Target_1.exe would be 0 and Target_2.exe maybe 0.5 at the most. This program reminds me of an exercise I had in a programming class once...

Try the crackme in the project area if you want something more interesting to crackg

ksbrace
February 8th, 2006, 13:03
Ok, I was reviewing everything and looking at the 2nd target in hiew and came up with the following question:
What would be the difference of changing a 74C5 to 75C5 as opposed to nop'ng out the 74C5. LLXX, had nop'd out this jump. I went back and changed it to 75C5 from the nops and it still appears to be working correctly. So, I'm just looking for clarification if both are acceptable or the nop is preferred, etc... I posted a small tidbit of the code below:
Code:

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0002.3AAA(U), :0002.3ACC(C)
|
:0002.3AD4 1E push ds
:0002.3AD5 B81469 mov ax, 6914
:0002.3AD8 50 push ax
:0002.3AD9 9ABD431B29 call 291B:43BD
:0002.3ADE 59 pop cx
:0002.3ADF 59 pop cx
:0002.3AE0 8BF0 mov si, ax
:0002.3AE2 3DFFFF cmp ax, FFFF
:0002.3AE5 74C5 je 3AAC
:0002.3AE7 1E push ds
:0002.3AE8 B85D69 mov ax, 695D
:0002.3AEB 50 push ax
:0002.3AEC 9ABD431B29 call 291B:43BD
:0002.3AF1 59 pop cx
:0002.3AF2 59 pop cx
:0002.3AF3 8BF0 mov si, ax
:0002.3AF5 1E push ds
:0002.3AF6 B87069 mov ax, 6970
:0002.3AF9 50 push ax
:0002.3AFA 9ABD431B29 call 291B:43BD

SiGiNT
February 8th, 2006, 13:10
The only difference is if you nop it then there is no chance that the jump will be taken, same with changing a JNE to JMP if you want it to jump or nop if you don't - either is acceptable but from what I've seen nopping and hard jmps are the preferred method.

SiGiNT

LLXX
February 8th, 2006, 16:01
Inverting jumps will invert the behavior, of course. What was once a target that loved the dongle will now detest it, and refuse to run *with* the dongle. If you find this situation of a program that hates dongles interesting and slightly humorous, then go ahead. Otherwise, forcing the logic is the best way, as it is now indifferent to the presence or absence of the dongle.