|
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.
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. |
|