FileForums

FileForums (https://fileforums.com/index.php)
-   Game Coders (https://fileforums.com/forumdisplay.php?f=36)
-   -   Infernal - Trainer & Gadgets (https://fileforums.com/showthread.php?t=80545)

کunβeam 15-04-2007 19:00

Infernal - Trainer & Gadgets
 
Starting with a basic trainer, and evolving/expanding the project in time once I discover more. I'll keep a diary of what I did, so others benefit from this experience. Also, adding some stuff I discovered while analyzing the game or its files. Hope this board allows constant editing of same post (I'd hate to double/triple post)

First off, let me say that I've tested all the trainers available for this game and all of them have only one option available (Unlimited ammo), and even so, that option is global (works for both player and enemy). Well, if they also had god mode, it wouldn't have been a pain in the ass to have enemies with Uzis shooting constantly on your ass :)

Therefore, I've been trying to conceive an ammo feature for the last few hours, and since I couldn't find a base pointer for my player (it shifts like mad, even though the game doesn't use code-shifting), I decided to call in for ingenuity and use another method :X Kinda g4y, but it works pretty nice.

Let me show you what I'm talking about...


[ Diary log #1 ]


Both the enemy and I are using the same function, located here :

http://i14.tinypic.com/49krps0.jpg

That's the code that would normally appear amongst others in your debugger window, when you're trying to see what writes to your ammo address.
Quote:

sub [eax+538], ecx

// eax = player ammo pointer
// 538 = weapon slot offset
// ecx = the amount deducted from your weapon's ammo
All nice and fine till here. If you nop that sub, both you and your enemies will have unlimited ammo. That's what all the trainers available on gamecopyworld (haven't checked if CH has one - sheep might beat the crap out of this game) do...

We want it one sided, and for that, also taking into account that I wasn't able to find a base pointer for the weapon pointer, I used something else. Noticed this :

http://i12.tinypic.com/351d2kl.jpg

Interesting - "enemy" - that word appears whenever the enemy uses that sub. Problem is the syntax is not always in the same manner. For instance, the pistol will always be "Enemy-pistol-ammo-..." while testing for Uzi, I saw "UZI-ammo-enemy-..."

In case you don't follow so far, I'll use word comparing :) So far - I'm at level 3, where you have to gain access in a cathedral by blowing its walls, right after Doctor Wolf flies out in a chopper - I haven't encountered a weapon to have the letter y in its description, therefore, the script :) - I hope you have Cheat Engine 5.3 installed !
Quote:

[ENABLE]

alloc(cave,256)
label(back)
label(loop)
label(out)
label(enemy)

//9B8140:
cave:
pushad
loop:
mov bl, [eax+14]
cmp bl, 79
je enemy
cmp bl, 0
je out
inc eax
jmp loop
out:
popad
jmp back
enemy:
popad
sub [eax+538],ecx
jmp back

5CC158:
jmp cave
nop
back:

[DISABLE]

5CC158:
sub [eax+538],ecx

dealloc(cave)

Time to explain what it actually does, and I'm going to sparse it in pieces, so you get the whole idea :

---
[ENABLE]/[DISABLE]

This is common CE syntax, pretty much and quite similar to ON/OFF. What's below the [ENABLE] tag will work as enabling the cheat/turning on the feature. The script will perform, once assigned to your cheat table, what ever is written below the [ENABLE] tag. How far ? Till the [DISABLE] tag. Same thing goes for [DISABLE]. What ever's under it will be written once you deactivate the script (tick/untick in your table). [DISABLE] works as "restore all" feature, except it restores only what you assign under it.
---
alloc(cave,256)

CE allows users to allocate memory of different sizes, which is pretty easy to work with, removing the worry to have to find an empty cave to write your code in. The syntax is as follows : alloc(name,size)
---
label(back)
label(loop)
label(out)
label(enemy)


The use of labels is also possible. Using labels you can set "waypoints" in your code to work faster and easier. Syntax : label(name) - note that numbers aren't supported in any name.
---
dealloc(cave)

The memory you allocate can be easily deallocated. It's also useful to use this code at the end of your script, since the allocated address will always be the same. If you don't use it, CE will keep allocating different addresses to your cave.
---
[DISABLE]

5CC158:
sub [eax+538],ecx

dealloc(cave)


This is the original code, and that's what CE will write when I disable the option. It's the equivalent for a "turn off the cheat" option.
---

Now to the main "plot" :

cave:
pushad
loop:
mov bl, [eax+14]
cmp bl, 79
je enemy
cmp bl, 0
je out
inc eax
jmp loop
out:
popad
jmp back
enemy:
popad
sub [eax+538],ecx
jmp back

5CC158:
jmp cave
nop
back:


What will the code do is to copy the string I mentioned earlier (Enemy-pistol-ammo-standard-8237) letter by letter and move it in a register, then compare it against the letter y. If that letter is encountered when scanning the string, perform normal code. If not, skip the sub [eax+538],ecx instruction. If the sub is skipped, we don't get anything deducted from out ammo, therefore one-sided unlimited ammo...

---
cave:

That is the address I've allocated at the beginning. The syntax for writing to it is : name: Basically, you tell CE to write at address "name", in my case at address "cave" :)
---
pushad

Saving the state of the registers, since we'll perform operations and use them. It's always nice to save the state, as the game might crash if one of the registers you use is overwritten.
---
loop:

This is the first label I declared. Labels can be used as addresses, or part of a code. In this case, "loop" will be an address located immediately below the "pushad". You'll see how the full code looks like in the end.
---
mov bl, [eax+14]
cmp bl, 79
je enemy


I chose to work with ebx, and since I'm operating with letters (bytes), I'll use the lower part of ebx (32b), which is bx (16b) and can be sparsed in 2 (bl, bh - both on 8b). 'l' for lower, 'h' for higher. The text string you saw in the 2nd picture is located at eax+14. The pointer is eax, eax+14 is the address holding the string. So - move in bl the first byte found at address eax+14 -> mov bl, [eax+14].

Further on, on the 2nd line, we compare bl with 79 (letter "y" in hexa). If they match (if y is found within the string), jump to label "enemy", where the game will allow their ammo to decrease :)
---
cmp bl, 0
je out
inc eax
jmp loop


If bl is not 79, compare it against 0. In case you haven't noticed, we only need to compare the string and stop after it. Or we'll hit an endless loop, and game will freeze. So, the cmp I added will check if the whole string has been "scanned" and stop at first 0 that's encountered. If bl is 0, jump to label "out", where the game executes a code that misses the "sub", therefore we don't get any ammo deducted. If bl is not 0, increase our pointer to move on to the next spot, and return to label "loop" to go through the function again, till the whole string is read.
---
out:
popad
jmp back
enemy:
popad
sub [eax+538],ecx
jmp back


Label "out" defines another address in the cave, at which we land from the jump mentioned above. We use "popad" to restore the state of the registers and allow the game to get back in "flow" :) Once the code is used, we jump back to address "back" (you'll see below)

The other label does the same thing, except it does it for the case in which the letter "y" is found in the string.
---
5CC158:
jmp cave
nop
back:


Our original address 5CC158: at which we write what's below it. The original code has 6 bytes (count them in the 2nd pic). A jmp uses only 5 bytes, so we'll use a nop to even out the code. 5+1=6. As I said above, once the out/enemy labels are used, at the end of each other you see "jmp back". Well, if you look at the code, I used in the function "back:" which defines an address located below the "nop". Therefore, "jmp back" means - jump to the address located below that nop. Since the sub had 6 bytes, "jmp back" means jump to 5CC158+6. Hope it's clear...
---

Phew. Long article. Once you copy the script, open up Memory View, press Ctrl+A and paste it the auto-assembler window. From the top menu (in that window), choose "Assign to table". Then check you table. You'll see what I meant with ON/OFF :) Ticking the checkbox in front of the script means ON/ENABLE. Unticking it equals OFF/DISABLE.

Time to show you how it all looks like :

http://i17.tinypic.com/4dlmz9u.jpg

Hope now it's understood.

کunβeam 15-04-2007 19:26

Hmm. Yeah, double-posting because :

- it needs a separate post;
- I got past the 12 images limit;

So, before judging, read the above :P

Anyway, was analyzing the file in looks for a clue regarding game's version. I don't want to go in-game, so I poped up PE Explorer. Since right-clicking the file and checking "Properties" didn't show a thing about the file, I used that tool.

Surprise :

http://i18.tinypic.com/2cicump.jpg

I've played this game a while ago, it's made by JoWood. Interesting - Archangel...

As for the version, I could only get this out :

http://i11.tinypic.com/2ivbr6v.jpg

Digging on. They use SolidShield, hah...

DABhand 15-04-2007 19:46

Woulda been better in the coding section, only the lesser minded come into this area :P


But saying that is the game not using static addies to store pointers for players and enemies?


Remember the health injection I wrote about Fable. Similar to that perhaps?

کunβeam 15-04-2007 20:24

Haven't read that. I'll start looking for it. Might be. Thing is, with Infernal, I actually found a trace, but it needs more in-depth research.

For instance, sub [eax+538],ecx had a "brother" up ahead like :
Quote:

mov edx,[esi+56C]
...
mov eax,edx
sub [eax+538],ecx
So, if you look at that, you got 2 offsets : 56C and 538. I looked in-depth for a stable link to esi. Searched for a pointer to it, and found plenty (about 600). Debugged it and all I got were opcodes like "mov eax,[edi]" =| I eventually found a pointer for it, was level 3. Kinda like : B6xxxx + 2F0 + 56C + 538. The pointer was static, but once I changed level or reloaded, everything died. Come to think about it, if this game is similar to Archangel in engine, it's all kinda self-explained. I remember I hit the same issues while playing that game...

I think the method I wrote about is quite simple. I'll read your Fable article, and see if I can find anything matching my situation :)

Oh, almost forgot !

Infernal command lines :

1. /window - start the game in windowed mode (I believe it's 800x600)
2. /safe - start game in safe mode (for some reason, I get an error msg box stating I have to reinstall the game - yeah, missing some files)
3. /nops - am yet to discover what this does (no p - player? - s - something?)
4. /ulkytutft67gfj655gy - no, it's not a joke, it's a command line - I believe it's used to disable some debugging protection features from both LUA/SolidShield - still checking :)

Enjoy ! I'll be back later...

P.S.: Once this thread gets big, you can move it to the Coding section.

P.S.2: Looking for a way to pop that window up - the one you see in that PE Explorer pic :)

TippeX 15-04-2007 23:05

why the pushad when you're only using bl

push ebx / pop ebx would be quicker..

also you aren't strictly checking for 'enemy' you're just checking for 'y'
that will probably lead to some false positives being hit and the game
acting strangely..

کunβeam 15-04-2007 23:29

As I said, I'm checking for 'y' because so far there isn't any weapon that has 'y' in its description. In this case, it works, but for other games I might get pwned :)

Also, I used pushad because I got "burnt" in lots of times. For example, I was training Thief 2 (I'll make an article about it) and I used as you said "push/pop register". I reached to this secret door which was getting opened by a lever. Once pulled, the door wouldn't open. If I used pushad/popad, it did open :) It's a matter of registers synchronization. At state_1, register_1 is value_1. If I push only register_1, the other ones will change state, and once register_1 is poped, the state will get fuxxed. Using pushad/popad I'm making sure the whole state is restored (even flags - ooops, that's pushfd/popfd, my bad).

Returning to the other issue, I've tested the option thoroughly, and I haven't got any false positives :) Player's ammo is clean in text, while the AI's ammo always has "enemy" in the string. Letters 'e', 'n', 'm' are also found with ease in one such string. Letter 'y' is only found at the end of the word 'enemy' and doesn't have any other instance in the string. I got lucky :P

TippeX 16-04-2007 01:42

using pushad/popad is just a workaround then, oh and eflags is NOT stored with pushad thats what pushfd/popfd is for

i suggest you brush up on your asm code, there is a different reason for the pushad/popad workaround u do....

dont believe me on the eflags.. try this code then

xor eax,eax
pushad ; < eflags are now 0246h (C 0 P 1 A 0 Z 1 S 0 T 0 D 0 O 0)
inc eax ; < eflags are now 0202h (C 0 P 0 A 0 Z 0 S 0 T 0 D 0 O 0)
popad ; < restore the registers...

flags changed? hell yeh...

کunβeam 16-04-2007 02:53

I used to believe that pushad stands for push a-d (eAx, eBx, eCx, eDx - A<->D). But I was wrong :) Anyway, I stand true to my beliefs. Hope you don't mind :P

TippeX 16-04-2007 05:49

how can u stand true to your beliefs when i just showed you your beliefs were flawed, and that using pushad/popad is just a lame way of fixing a bug caused by bad coding...

POPA/POPAD - Pop All Registers onto Stack (80188+)
POPF/POPFD - Pop Flags off Stack

so its a bit more than a->d
also it is not flags, flags are a different opcode...

why not actually properly learn asm, and the mnemonics, then start teaching eh?

کunβeam 16-04-2007 10:38

I was sure you'd get me wrong :) I stand true to my beliefs of using pushad rather than normal push. I am aware it doesn't store flags. It isn't lame, it is just logics. You want to tell me if I push/pop a register, the original state will remain unchanged after the pop ? What will happen with the rest of the registers while I push only one ? They don't get saved. So, by the time I pop it, the others would've changed...

I know ASM so far as game training requires it, am not a pro @ it, nor do I like to use excentrisms and talk like "Yeah, but your code isn't 100% ergonomic" or "I could've done better". I am aware there's always room for better.

Also, most of the people are so comfortable nowadays that they like to just reply to others about their flaws/"mistakes", instead of putting their own HAND to writing and explaining. Oh, don't worry, we'll understand it, as complicated as you'd explain it. Show me a really good tutorial that trains a game properly (I mean new games - 2006/2007) and I'll start taking notes...

Sorry if I sound incisive, it's not oriented towards you, it's just that everybody's on my ass lately, no matter how good a post would look like. If I write a code, and post it, those who don't know ASM at all will take it as is. Those who are pro at it will always find room for better and want me to perfect the code to suit their "needs" (they don't actually use the code, but rather enjoy debating around it to no avail)...

One way or another, the code I posted is operational, and as lame as it looks like, it's working - yes, I know, only for this game...

@Tippex: I have a request out of you. Take that code I posted, and make it better. Don't go heuristics like "You should use a player pointer", since I am aware of that. Just that code I posted, your version. Please :) Am curious what changes you'd addition to it. It's not a sarcastic request, but more like a "trying to grasp more XP" request :)

You got all you need : the address to jump from, string location, etc...

TippeX 16-04-2007 11:06

i dont do requests, and i also do not have to prove myself.. been there, done that

if you push / pop a register then yes, it will be preserved, thats the whole poinf of the opcode, when coding especially at asm level, the register preservation (and in some cases) flags are for YOU to maintain... most api's will definately destroy eax, ecx and edx.. ebx is usually used within windows messaging and within callback procedures..

fundamental flaws in the code would be your looping
inc eax, could lead you well out of the memory boundaries that would be my only cricicism.. but in trainers, especially with what you're doing its important to preserve / set the flags
take for example your little bit of code, see the sub at the end, thats going to effect the flags and could well screw the game up, as it might branch when it shouldnt etc.. thats where the difference between good code and bad code comes in.... stack balancing + register preservation, is very important

کunβeam 16-04-2007 11:13

I didn't ask you to prove yourself. I was curious how would your version of that code look like. Also, how would eax go out of the boundaries, when : [1] it's stacked; [2] it only increases so far as bl is not 0; [3] eax gets restored, so nothing crashes; [4] the sub uses the pop'd eax...?

Yeah, I agree - god damn stack gave me so many headaches back in the days. And it still does. Pretty powerful thingie.

Joe Forster/STA 16-04-2007 11:37

(I pity people who have to learn ASM on a relatively sophisticated platform as the x86 CPU and DOS/Windows. Back in the microprocessor days, a Z80 was much easier to understand, not to mention the even simpler good old 65xx series.)

caki 16-04-2007 13:55

Wow, this section is actually seeing some action :)

TippeX 17-04-2007 01:05

Quote:

Originally Posted by کunβeam (Post 340067)
Also, how would eax go out of the boundaries, when : [1] it's stacked; [2] it only increases so far as bl is not 0; [3] eax gets restored, so nothing crashes; [4] the sub uses the pop'd eax...?

okay, here goes, u say eax = stack.. fine
cave:

pushad ; preserve registers
loop: ; loop begin
mov bl, [eax+14] ; okay, eax supposedly on the stack
cmp bl, 79 ; is bl = 79
je enemy ; if so, boing out of this routine
cmp bl, 0 ; is bl = 0 (presumably end of string)
je out ; if so, boing out
inc eax ; incriment our pointer by 1
jmp loop ; loop << this is where u can cause a crash eax may be on stack, but the stack does have limits, and this could be reproduced by puting crap in eax
out:
popad ; restore the registers
jmp back ; get out
enemy: ; enemy portion
popad ; restore registers
sub [eax+538],ecx ; and do the mathy thing
jmp back ; then get out

back:


flags not preserved, the sub [eax+538], ecx can adjust the flags

Quote:

[2] it only increases so far as bl is not 0;
erm, it only increases as far as when byte @ [eax] = 0, it will keep going on until this happens or it finds the 'y'

what i would do is check that the byte @ eax fits within an 'acceptable' character range, then i would do an lstrlen or so on it to calculate its length and work from that... its relatively safer..

like check it fits within 'a->z/0-9' or 'A->Z /0-9' then begin processing
the game could act on the flags, from the code, so the cmp, etc can screw
the flags, ideally what u want to do is to set the flags for when u handle the player portion, (where u set the flags to a good condition), and leave them as-is for the enemy portion..

such code could be like

call check_ammo_amount ; this would be the code that you patch
jz user_has_no_ammo

etc..
where the flags are DEFINATELY important, it depends on how the game was coded, but its worth paying attention to..

and i guess u can pity me joe, cos i started out in the dos days, interrupts, 8 bit, 16 bit, pmode... all fun to learn though :)


All times are GMT -7. The time now is 15:16.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2026, vBulletin Solutions Inc.
FileForums @ https://fileforums.com