My current ICQ-online Status
About author
My Family
Slovenia
Local area
Cockpits
My Programs
Procedural textures
Falcon4
Hacks
Encryption
Siege of Power
World in Flames
Hacking programs

  OK. If you wanna hack a program, first thing you oughta know is exactly what you`re looking for. You have to think well how you yourself would do that thing, or what would be the best way to achieve it. You have to picture it all up.

Second, you gotta know where to look. If it`s a code it would probably be in an EXE (or OVL in older programs) file, but you can check other files too. If it`s data it can be packed as constants inside an EXE file or in a outside data structures. You just get yourself a HEX editor, you can use Microsoft Developer Studio as debugger also, but much better is kernel debugger NuMega SoftIce.

Then you have to search inside a file for a teeny tiny string where all that is written. You can write your own programs to do the job. If you`re not sure if you found the right thing, the best way to figure that out is to corrupt that part. If program freezes, then you`re wrong (or right in some cases). If you get expected results, then you`ve hit with the hammer on a nail.

Modify that string ... and voila!


CASE 01, Falcon 4 code hacks
FALCON 4.0


I started developing ADSCockpits patch (Aircraft-Dependent Switchers group) for Falcon4TM as a result of the last official iBeta executable not being able to switch between cockpits automatically.

ADS was designed for modular integration of its subparts to avoid future changes when new additions are made.
 

Instructions on EXE hacking and explanation of my work.

To be able to do some exe hacking you must first understand 8086 32bit assembly language very well. You will obtain this knowledge only by vast ammounts of programming in this low level computer language.

Next thing you need is some kernel debugger, I for example used Softice. Kernel debugger will allow you to break into Windows or any other program routines on instruction, memory R/W or hardware breakpoint.

The thing that made cockpit switching (2D cockpit switching) in Falcon4 possible is that 2D pannels graphics files are zipped in an archive (CPdata.zip) and this file is unzipped every time before player enters cockpit. Unzipping doesn`t take place if there are allready files unzipped in directory \art\ckptart\.
Exploitation of this last fact was used by some manual switchers. To manually switch cockpit, you had to exit the game, this manual switcher then deleted the contents of art\ckptart\ folder and copied new cockpit files into it.

My basic idea was, if all possible cockpits exist each in its own directory (named by aircraft type) instead of copying files into target directory, why not order Falcon4 to search for a different target directory depending on aircraft being flown.

=========
Now a little bit on exe files.
EXE file has a header, where it is written to which address in memory it should be read. Normally exe files are read into adress 0x400000. How does then exe file look like when in computer memory (RAM)? Exactly like when in file on disk. Bytes that are for example at file offset 1234 will be found in memory at adress 0x401234.
Next thing are segments. Falcon4 has three segments defined in its header.
.text segment is part of this exe, where hexadecimal numbers are interpreted as CPU instructions (code). This starts at 0x400000.
.rdata segment is rawdata area. Here CONSTANTS are baked into exe. At 0x788000 in Falcon4.
.data is third segment, the data segment. Here STATIC VARIABLES are stored. 0x7B0000 or something in Falcon4.

The area that is directly overwritten by exe file contents ends at offset 0x400000+filelength, that is 0x8xxxxx. Beyond this offset there is free memory which will be used for dynamic memory allocation (calling "new" operator or malloc function will return memory offset where enough free space has been allocated for your storage request).

Since .text and .rdata segments aren`t supposed to be changed, these memory pages are marked be the operating system as ReadOnly. If you accidently start writing over this data, OS will not allow you to proceed and program will terminate with Access Violation (Page Fault). This can of course be overriden by switching a few bits in exe file header telling OS .text and .rdata are RW (not RO). If you know what you`re doing this is OK (you can change program code on the fly) if not, you will dig your own grave.

For example, if you write a program and inside it you use a text string which defines a filename "myfile.txt", then this string "myfile.txt" will be hardcoded into exe as a constant. If you then want to use this name in fopen("myfile.txt","r") procedure, what compiler/linker does is it pushes offset of your constant on stack (in our case it should push offset of string "r\0" and then offset of "myfile.txt\0" - say they reside at 0x790000 and 0x790008) and then it calls function fopen (which is also baked into your exe, say it is at memory offset 0x412340).
Your call to
FP = fopen("myfile.txt", "r");
will be compiled and linked into
PUSH 00790000
PUSH 00790008
CALL 00412340
With this you pass locations where fopen procedure can find your zero-terminated strings.
Since fopen returns a value (return values are allways passed in EAX register) and since you want to use it (you store it into variable FP, otherwise contents of EAX would be discarded) this will follow:
MOV [007B0000], EAX
This line will store contents of EAX onto memory cells at offset 0x7B0000. Linker knows there is your STATIC VARIABLE "FP". If you initialize this FP to be NULL (i.e. 0x00000000) then four bytes at file offset 0x3B0000 will be zeroed, thus when exe is loaded into memory bytes at offset 0x7B0000 will be 0.
=========

The third thing that made 2D cockpit switching possible is that strings defining file locations (locations of unzipped cockpit files) were STATIC VARIABLES and not constants. If names were constants, then by attempting to change them, you would cause a page fault. But since they were a part of .data segment, they were allowed R/W.

If we take a look at directory where cockpit files should be:
\art\ckptart\

We see that we can easily sieze 5 characters to define our aircraft name. We change hardcoded directory names into
\art\c\xxxxx\
where "xxxxx" define a default subdirectory in \art\c\ folder. Inside this xxxxx directory default cockpit files will be stored, and used by all aircraft that do not have thir own cockpit files. If aircraft has its own cockpit files, then a new subdirectory will be created and pointed to.

How exactly to do this.
There is a Falcon4.VCD (vehicle class data) file. Inside it there is some data on vehicles (ground, air and naval). When user selects a flight s/he wants to fly, Falcon4 also determines a pointer to its VCD data record. With other words, if you choose to fly a MiG-29, when you select this flight, a pointer to memory location holding MiG-29 VCD data record will be calculated in a process.
If we capture, intercept this pointer, then we know what aircraft we`ll be flying. And furthermore, inside VCD data record there are 20 bytes long strings holding the name of this vehicle type. If we shorten these names to be max 15 characters long, then we have 5 bytes for each vehicle where we can define the directory name this vehicle`s cockpit files.

So, when user changes flight, VCD pointer is intercepted. We then look at relative offset 0x17 where our cockpit namestring shoud be. If namestring is 5 characters long (all chars are within range 0x20-0x7F) then name is assumed as valid. If not, then first four characters are checked. If still not OK, then default name "xxxxx" is assumed.
We then go through memory and overwrite all strings that have something to do with cockpit directory names. We change them from "art\c\xxxxx" into say "art\c\MG29A".

With this we effectively forced Falcon4 to automatically look for cockpit files in directories specified inside VCD data file, instead of hardcoded directory.

Why 5-letter 4-letter check?
Because Hoola and Marco Formato needed 4 characters to implement NCTR identification for F-16. I gave them first 4 characters, which define NCTR IDs (like F16, MG29, MG21, F5, TPT...). If fifth character is not zero, then cockpit exists for this aircraft. This also helps me, because there is no need to have one cockpit installed two times (for F-4E and F-4G for instance) if we leave the fifth character zero (both F-4s will use cockpit installed inside "art\c\F4__")
 
 

IMPLEMENTATION
 

void
Load_C3D_MFD_HUD_File (void)
{
// LIMIT 786100
/*
Arg
	[EBP+8]		int		Type (00000000=MFD/C3D, POINTER=HUD/RWR/MFD)
	[EBP+C]		char	*Ext
Var
	[EBP-4]		int		RecNo
	[EBP-8]		int		Size
	[EBP-C]		int		Dest
	[EBP-10]	int		FHANDLE
	[EBP-14]	char	*PtrMidName
	[EBP-210]	char	*TempStr
*/
	__asm{
			xor		eax, eax
			xor		eax, eax
			xor		eax, eax
			xor		eax, eax
			nop
			nop
			nop
			nop
			nop
	}
	__asm{
		PUSH	EBP
		MOV		EBP, ESP
		SUB		ESP, 0x210

	// Dealloc first
		MOV		EAX, [EBP+8]
		TEST	EAX, EAX
		JZ		DEALLOC_END
		MOV		EAX, [EAX]
		TEST	EAX, EAX
		JZ		DEALLOC_END
		PUSH	EAX
		MOV		EDX, 0x40E390
		CALL	EDX
		ADD		ESP, 4
		MOV		EAX, [EBP+8]
		MOV		dword ptr [EAX], 0
DEALLOC_END:

	// Setup filename
		LEA		EDI, [EBP-0x210]
		// "F:\Falcon4"
		MOV		ESI, 0x7DAD7C
FL_Falc:
		LODSB
		STOSB
		CMP		AL, 0
		JNZ		FL_Falc
		DEC		EDI
		// "\art\c\"
		MOV		ESI, 0x798D60
		MOVSD
		MOVSD
		DEC		EDI
		MOV		[EBP-0x14], EDI
FL_CC:
	// Try open Current Cocokpit Name
		MOV		ESI, 0x798D98
		LODSD
		CMP		EAX, 0x78787878
		JE		FL_VCD
		STOSD
		MOVSB
		MOV		ESI, [EBP+0x0C]
		MOVSD
		MOV		byte ptr [EDI], 0

		PUSH	0x8000
		LEA		EAX, [EBP-0x210]
		PUSH	EAX
		MOV		EDX, 0x415C11
		CALL	EDX
		ADD		ESP,8
		MOV		[EBP-0x10], EAX
		CMP		EAX, 0xFFFFFFFF
		JNE		FL_LOAD

FL_VCD:
		MOV		EDI, [EBP-0x14]
	// Try open VCD Name
		MOV		ESI, 0x798D94
		MOV		ESI, [ESI]
		TEST	ESI, ESI
		JZ		FL_Default
		ADD		ESI, 0x17
		MOV		EDX, 4
FL_VCDR:
		LODSB
		STOSB
		CMP		AL, ' '
		JZ		FL_VCDE1
		DEC		EDX
		CMP		EDX, 0
		JNZ		FL_VCDR
		JMP		FL_VCDE
FL_VCDE1:
		DEC		EDI
FL_VCDE:
		MOV		ESI, [EBP+0x0C]
		MOVSD
		MOV		byte ptr [EDI], 0

		PUSH	0x8000
		LEA		EAX, [EBP-0x210]
		PUSH	EAX
		MOV		EDX, 0x415C11
		CALL	EDX
		ADD		ESP,8
		MOV		[EBP-0x10], EAX
		CMP		EAX, 0xFFFFFFFF
		JNE		FL_LOAD

FL_Default:
		MOV		EDI, [EBP-0x14]
	// Try open XXXXX Name
		MOV		EAX, 0x78787878
		STOSD
		STOSB
		MOV		ESI, [EBP+0x0C]
		MOVSD
		MOV		byte ptr [EDI], 0

		PUSH	0x8000
		LEA		EAX, [EBP-0x210]
		PUSH	EAX
		MOV		EDX, 0x415C11
		CALL	EDX
		ADD		ESP,8
		MOV		[EBP-0x10], EAX
		CMP		EAX, 0xFFFFFFFF
		JE		FL_End

FL_LOAD:
		PUSH	4
		LEA		EAX, [EBP-4]
		PUSH	EAX
		MOV		EAX, [EBP-0x10]
		PUSH	EAX
		MOV		EDX, 0x41594E
		CALL	EDX
		ADD		ESP,0x0C
		CMP		EAX, 0
		JE		FL_Close

		CMP		dword ptr [EBP+8], 0x00000000
		JNE		FL_TYP_HUD

FL_TYP_C3D_MFD:
	// If we have C3D/MFD type of file
		CMP		dword ptr [EBP-4], 0
		JE		FL_Close
FL_Repeat:
		MOV		dword ptr [EBP-0x0C], 0
		LEA		EAX, [EBP-0x0C]
		PUSH	8
		PUSH	EAX
		MOV		EAX, [EBP-0x10]
		PUSH	EAX
		MOV		EDX, 0x41594E
		CALL	EDX
		ADD		ESP,0x0C
		CMP		EAX, 0
		JE		FL_Close
		MOV		ECX, [EBP-8]
		MOV		EBX, [EBP-0x0C]
		ADD		EBX, 0x400000
		//CMP		EBX, 0x798000
		//JB		FL_Break				// SKIP, causes a CTD
		LEA		EDX, [EBX+ECX]
		CMP		EDX, 0x8A0000
		JA		FL_Break
		PUSH	ECX
		PUSH	EBX
		MOV		EAX, [EBP-0x10]
		PUSH	EAX
		MOV		EDX, 0x41594E
		CALL	EDX
		ADD		ESP,0x0C
		DEC		dword ptr [EBP-4]
		JNZ		FL_Repeat
FL_Break:
		JMP		FL_Close

FL_TYP_HUD:
	// If we have HUD type of file
FL_ALLOC:
		MOV		EAX, [EBP-4]
		PUSH	EAX
		MOV		EDX, 0x40E370
		CALL	EDX
		ADD		ESP, 4
		MOV		EDX, [EBP+8]
		MOV		[EDX], EAX
		TEST	EAX, EAX
		JZ		FL_Close

		MOV		EDX, [EBP-4]
		PUSH	EDX
		PUSH	EAX
		MOV		EAX, [EBP-0x10]
		PUSH	EAX
		MOV		EDX, 0x41594E
		CALL	EDX
		ADD		ESP,0x0C
	// Correct internal pointers
		MOV		EAX, [EBP+8]
		MOV		EAX, [EAX]
		MOV		ECX, 0x40
		MOV		EDX, EAX
FL_Check:
		CMP		dword ptr [EDX], 0x400000
		JGE		FL_Skip
		ADD		dword ptr [EDX], EAX
FL_Skip:
		ADD		EDX, 4
		DEC		ECX
		JNZ		FL_Check

FL_Close:
		MOV		ECX, [EBP-0x10]
		PUSH	ECX
		MOV		EDX, 0x41572B
		CALL	EDX
		ADD		ESP,4
FL_End:
		MOV		ESP, EBP
		POP		EBP
		RET
	}
	__asm{
			xor		eax, eax
			xor		eax, eax
			xor		eax, eax
			xor		eax, eax
			nop
			nop
			nop
			nop
			nop
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/*
void
Calculate_VCD_vehicle_index (void)
{
	Load VCD pointer to our record
	Load VCD pointer to the start of VCD structure
	Divide the difference with the size of record to determine VCD index
	Store VCD index.
}
*/void
Calculate_VCD_vehicle_index (void)
{
// LIMIT 4044F0
	__asm{
		// Load VCD pointer
		MOV		EAX, [VarD]//[94 8D 79 00]
		SUB		EAX, [VarD]//[1C AB 7D 00]
		XOR		EDX, EDX
		MOV		EBX, 0xA0
		DIV		EBX
		// Store VCD index
		MOV		[VarD], EAX//[90 8D 79 00]
		RET
// LIMIT 40450C
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/*
void
Validate_Directory_Name_and_store(void)
{
	Grab the 5-byte name at the end of the VCD record
	Check it if it contains characters between ' ' and 'z'.
	If not, assume default name "xxxxx".
	If ' ' character is encountered, change it to '_'.

	Store new 5-byte name to [98 8D 79 00]
}
*/
void
Validate_Directory_Name_and_store(void)
{
// LIMIT 404510
	__asm{
		// VCD Pointer
		MOV		ESI, [VarD]//[94 8D 79 00]
		// NCTR+ADS String
		ADD		ESI, 0x17
		// Currnet Cockpit
		MOV		EDI, 0x00798D98
		MOV		EDX, 5
VDN_Loop:
		// Compare if all characters can be used in Windows OS directory names
		LODSB
		CMP		AL, 'z'
		JG		VDN_Break
		CMP		AL, ' '
		JL		VDN_Break
		CMP		AL, ' '
		JA		VDN_Copy
		// If Space is encountered, convert it to an underscore
		MOV		AL, '_'
VDN_Copy:
		STOSB
		DEC		EDX
		JNZ		VDN_Loop
		MOV		EDI, 0x798D98
		RET
VDN_Break:
		MOV		EDI, 0x798D98
		MOV		EAX, 0
		MOV		[VarD], 0x78787878//[98 8D 79 00]
		MOV		[VarB], 0x78//[9C 8D 79 00]
		RET
// LIMIT 404570 
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/*
void
SwitcherManager (void)
{
	//	Intercept it in SinglePlayer or MultiPlayer mode
	//	Intercept pointer to something ... I don`t know what
	//	Run this pointer through two functions and you get out a pointer 
	//	to VCD structure loaded into memory
	//	Pointer now points to the start of the record of the type of aircraft you wanna fly
	
	//	Store VCD pointer
	[94 8D 79 00] = VCDPtr

	//	Calltable slots
	Calculate_VCD_vehicle_index ();
	Validate_Directory_Name_and_store ();
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
	-- Empty --
}
*/void
SwitcherManager (void)
{
// LIMIT 404570
	__asm{
	// Single player and Servers - Entry point
	// Old code we need to execute
		POP		EDI
		POP		ESI
		PUSHAD
	// Get our chosen flight data
	// flight = FalconLocalSession->GetPlayerFlight();
		MOV		EDI, [VarD]//[DC CD 84 00]
		TEST	EDI, EDI
		JZ		SM_End
		ADD		EDI, 0x000001D4
		MOV		EDI, [EDI]
		MOV		ECX, EDI
		CMP		ECX, 0x400000 
		JL		SM_End
		JMP		SM_Code
	// Slave machines - Entry point
		POP		ESI
		POP		EBX
		PUSHAD
	// flight = FalconLocalSession->GetPlayerFlight();
		MOV		EDI, [VarD]//[DC CD 84 00]
		TEST	EDI, EDI
		JZ		SM_End
		ADD		EDI, 0x000001A4
		MOV		EDI, [EDI]
		MOV		ECX, EDI
		CMP		ECX, 0x400000
		JL		SM_End
SM_Code:
		PUSH	0
		MOV		EDX, 0x4AA440
		CALL	EDX
		MOVSX	EAX, AX
		MOV		EDX, 0x4BB6F0
		PUSH	EAX
		CALL	EDX
		ADD		ESP, 4
		// Store VCD pointer
		MOV		[VarD], EAX//[94 8D 79 00]
SM_CallTable:
SM_Slot00:
		MOV		EDX, 0x404510
		CALL	EDX
SM_Slot01:
		MOV		EDX, 0x4044F0
		CALL	EDX
SM_Slot02:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot03:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot04:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot05:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot06:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot07:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot08:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot09:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot0A:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot0B:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot0C:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot0D:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot0E:
		MOV		EDX, 0x0
		NOP
		NOP
SM_Slot0F:
		MOV		EDX, 0x0
		NOP
		NOP
SM_End:
		POPAD
		RET		4
// LIMIT 404650
	}
}




CASE 02, Falcon 3 data crack

 
I wanted to modify a flight simulation so, that it would be possible to use nucear weapons.
That required me to change some numbers inside the program.

To effectively change a weapon I had to change all data connected to it. That would be:

  • Weight of weapon
  • Aerodynamic drag factor
  • Strength of weapon
  • Units-per-pylon data
  • and other stuff, guidance, warhead type, ignition delay, max G-force turn capability...
First I took a look at filenames. I got attracted to files named ARMSxxxx, lots of them. The best way to find something is to know how it looks like. So I went searching for weapon weight. I picked one weapon, its weight let`s say was 500 pounds.
To write down a number 500 in binary you have a few options. BYTE variable is invalid, because it can reach only up to 255. Next one is WORD and then DWORD type variables.
 
DEC
HEX
WORD
500
01F4
DWORD
500
000001F4

Then you also have an option to write it down in FLOAT or DOUBLE types. Consider this, but it ain`t a real possibility, just in special cases.

So, I chose to look at word variables. Be advised, inside the file (and memory - RAM) 0x01F4 is written in opposite order. If you wanna find a number 0x01F4 you have to search for string F401. (Similary, if you have to find a dword 0x12345678 you`d need to look for hex string 78563412. The same stands for floats=32 bit dword-like numbers and doubles=64-bit qword-like numbers).

Also keep in mind, that BYTE may be found on every byte-sized part of memory. A WORD, DOWRD, QWORD, float and double can only br found on addresses (offsets) that are multiples of two/four/eight (WORD/DWORD/QWORD data alignment). When writing programs it is a tendency to align data inside memory on DWORD alignment - multiples of 4. Because in 32-bit mode, all the registers are 32-bit. And 32-bit linear addresses are used to address physical memory. When you order processor to load a DWORD number into some register, if that number is NOT located on DWORD-alignment position, then processor needs additional time to addres it. So, when you write programs and create data structures, it is not wise to use BYTE variables if you expect numbers only up to 255. Because then, all the folowing variables will not be properly aligned, and if you`ll access such variables often enough, it will slow down your program very much.

OK. So now we`re searching for a word string F401. We make a special program, that writes down address of every match. Then we do the same for other weapons and manually compare the results. If we find that all the weapons have one of the results (that could be weight) inside (let`s say -512 + 512 bytes from some center point) an interval, then that`ll probably be it.

But with this method, you can get A LOT of results and you have to comare all that stuff.
It`s very nice if you know the order in which the weapons may be stored in memory. That order will probably be the order in which you see them in a game.



Well, back to searching. I first searched for weapon weights in them ARMSxxxx files. And found nothing. Then I went looking in the EXE file. And I got a lot of results.
So, I tried to predict the order of weapons. I loaded the EXE file into a HEX browser, and quickly looked over it. I ordered the browser to search for words like "AIM-9", a name for an Air-to-Air missile. And it found several hits. I took a look at them and found them on one place, all the names of the weapons. I used that order to search for weapon-weights.
So I wrote another special short program, which searches for a specific weight. When it finds one, then it looks for the others placed relatively to this one but at various offset multipliers. First 2 bytes, then 3 bytes and so on. This kind of calculation takes time. Approx an hour maybe (on my old 486), if the file is big.

I got reported hits. I went to check it out with HEX browser, and found all of the weapons WORD weight values stored in proper order. Well, not exactly. If you make a program that searches for a specific order, then you`ll find nothing. You have to write a program that reports a hit whenever it finds more than let`s say 3 matches. Then you just look at the number of matches and check the most probable ones.
I had this problem. Falcon 3 was an upgrade of Falcon 1.2. And it contained weapons that were infact not used.

OK. I found two places in file that contained weapons weights. So, which one is the correct one? Let`s corrupt it and we`ll see. I chose a specific weapon, and increased its weight to max (0xFFFF). Then I went into the game. When I chose that weapon in Load-Armament window, weapon data said the bomb weight was -32768 pounds. I corrected it to 0xFF7F (remember 0x7FFF=32767, in memory stored at opposite order), and loaded it on the aircraft. I went flyin` and the aircraft took off noramlly!
So, what the hell went wrong?! F-16 cannot take of with a 30000 pound cargo!
Then I corrupted the other string aswell. Bigo! Aircraft fell back on runway after takeoff.

The first string found was used ONLY by aircraft-armament procedures, the second string ONLY by the aerodynamics procedures.

Then I knew the order and where to look for. Next thing I had to correct was the weapon aerodynamic drag. Put in the search numbers and the order and there they were. String of BYTEs. Also on two places. One for load-armament and one for aerodynamics.



Now I had a bomb of correct weight and drag, instead of Mk-82-1 HDGP, I had a B-43 Thermo Nuclear Weapon. But I could still load 12 of`em on the plane instead of one.
So I went looking for the weapon-hardpoint data. 

Say, F-16 in game has 2 wingtip hardpoints, 6 underwing hardpoints and one under-fuselage hardpoint.

                                              I
                                              I
                                         AAAA
       o______________XXXXXXX______________o
               |      |       |                |                |       |      |
==========================================
       0     0     6      6               0               6     6     0    0          Weapon loadout for Mk-82-1

I had to look for a string (probably bytes) = [00 00 06 06 00 06 06 00 00] or [00 00 06 06 00].
And found one. Actually I found many of them, because several weapons have the same loadout numbers. I modify the correct one into [00 00 00 00 01 00 00 00 00].



Energy of weapon still needs to be modified. This one`s gonna be tough. It can be a BYTE, a WORD a DWORD or even a FLOAT.

I went into a game, and made several tests.
I shot every type of weapon into the ground so it left a crater. I recorded the whole thing on AVTR. Then I went to a replay mode, put the viewpoint at the specific distance from every crater and optically measured the size of each of`em. That gave me some clue, about which weapon is stronger (I created a ladder of weapon strengths, from the weakest one to the stronger one).Then I went to search for all types of variables in order mentioned above, with respect that specific vaues have to be bigger/equal/smaller than other specific values. And I found nothing.



I was looking in all possible ways, and had no luck.
I allready knew which part of the EXE file was doing what, so I searched again for the weapons names. And there was one string of names that didn`t fit in my suspected order. Besides, there were also other weapons, used by ground crews (Surface to Air missiles, enemy A-A missiles etc...)

Well, I just wanted to be sure. There were some suspicious numbers folowing that names. They looked like WORD values (y`know: 82 00 4F 00 23 00 12 00 35 02 05 00 E8 01 7F 00 ... where those very small numbers at even places just cry out that they are the HIGH BYTE of a WORD).
Oh well, I blanked them all, made them all 00 00 00 00 00 00 00 .... and went check that out to a game. I dropped a pair of Mk-84s from 500 feet (that should`ve blown my ass to pieces). But instead it just went "Booh...". So I dropped another pair from 100 feet, and nothing. BINGO!!! Weapon strengths! Mk-84 have minimum drop altitude something about 1500 feet. But their order was mixed up. So I had to tilt up ever one of them and check it out in a game.

I lined up a column of vehicles and shot weapons at it. Can you imagine an AIM-9P air-to-air missile with 20 pounds of explosives torching instantaneously up a one mile column of armored vehicles?
Well, I just had to pin-down my Mk-82-1 bomb, tilt it up to 0xFFFF, and test it.



I expected that the safe drop altitude will be 18000 feet or something. Noooo, it ripped my ass when it went off. So I tried again from 25000` then 30000` then I went almost berserk. 35000` and I still suffered an engine failure from the blast. Well at 40000` with 500 kts I was safe.
But from that altitude you cannot aim accurately. So, I setup a friendly flight at 1000 feet flying below me, then I dropped The Bomb, measured drop-time (until the guy below started screaming) and then measured the distance from release-point to crater.
 

And there you have them Nuclear Bombardment procedures.




CASE 03, X-wing code crack

 
Well, you cannot fly the StarWars X-wing / B-wing or Tie fighter simulation (the very old ones) with keys. That`s for sure.
And neither can you with mouse. Because them clever programmers baked into the program mouse commands that read out mouse velocity instead of mouse position.

I wanted to modify a flight simulation so, that it would read out mouse position instead of mouse movement-velocity (like joystick offset).



Every program (well DOS programs) communicates with mouse device through an interrupt. More specificly, that is the INT 33h (0x33). Depending on the task you want the device handler to perform, you put the number of that task (function) into AX register, if you need to send additional data to interrupt routine you put it into BX or DX or CX register and then you call INT 33. Piece a cake.

The assembly code would look something like that:
mov ah, something
mov al, something else
mov bx, something
int 33h

You can write that down into an ASM file, build an OBJect, and disassemble it again (or watch the assembled machine codes in the debugger or you can assebmle machine code manually if you know how). When you disassemble it, you`ll see exactly into what numbers (machine code) the assembly instructions are coded.

But first we need to find the area in program, where the mouse functions are. Again, we order the HEX browser to search for hex string CD 33 (0xCD is hex code for INT instruction, and 0x33 is the interrupt number). Of course we look for them in EXE file. And we find nothing. So we select all the files (the longer ones are more probable) and run the scan. And we find some hits in OVL files.
There are several ocasions where CD33 is used. Some of them may be coincidential, maybe data structures or something... But there ain`t many.
So we make an ASM file, where we have let`s say 2048 NOP (no operation) istructions. A verrrrry long text file. We compile it into a neutral OBJ file. This OBJ file will contain only 0x90 machine code (nop). Well, you have to check this OBJ with a hex browser first. Because inside an object file the code gets sliced up into segments (I think) 1020 bytes long. Inbetween there are some 5 bytes of data inserted. Besides, object file has a head. So you have to check out in exactly which areas you can replace the 0x90 instructions with new instructions.

When you know this, you just make a program that copies a part of surrounding code (around the match in OVL file) into this neutral OBJ file. Perserve the neutral OBJ file. The code you need to copy is not long. It will do if you copy -256 to +255 (512 bytes) around offset point.

Now`s the time for disassembly. You`ll get a new ASM file, with all instructions. You have to be carefull to define first whether it is an 16-bit or 32-bit code. (Easier procedre is to just look at it with some debugger at runtime)
When you`re looking at the code, be advised that the first few (3-4) disassembled instructions won`t be correct. This is because, the machine code can consist of 1 or more bytes. So, if you accidently cut the first instruction, the disassembler will interpret it wrongly. But, we`re not interested in the first few instructions. We`re interested in the main core. And that one will be correct.

So, now you need to visually identify if the code is right. You need to know assembly very well. If you see a bunch of stupid instructions (just randomly ordered instructions, that do nothing), then you`ve just disassembled a data structure.

If you see some sence in it, then you got it.
In my case, I got several functions inside my 512 byte perimeter. One was setting up mouse resolution, one was dealing with mouse velocity ... You have to recognize them by the numbers that are being loaded into AX register before calling INT 33.
So I took that function that was dealing with mouse velocity, and changed the AX parameters (from velocity-detection to offset-detection). But there was a problem. It was necessary for me to insert additional code there. Every function was only around 32 or less bytes long. So, not very much space to throw around. I was lucky there was a page-break or something just after the mouse functions. Just around 20 bytes of free space. So I inserted a JMP (jump) instruction to this free space into a function. I don`t remember very well what kind of code I had to insert. Something with movement resolution and max. limits. Well, there was just enough space to do that. I calibrated the results to be within 0-511 range. Next thing I`d need to get done was, a subtraction of 256 form the result, so I`d get a -256 to +255 range. But there was not enought space to insert a SUB command, and I had to forget about it. Then just a JMP back to the function and all is done.

Check it out here.




Page updated Mar. 19th 2002, (c) Miran Klemenc homepage, Ras Algethi, E-mail me
 
  Visitor no:Impact Counter since Sept. 14th 1999
1