Demo #16—Real-Time Expression Evaluator

Discussions Related to Game Hacking and Memory Hacking Software

Moderators: g3nuin3, SpeedWing, WhiteHat, mezzo

Demo #16—Real-Time Expression Evaluator

Postby L. Spiro » Tue Mar 06, 2007 12:09 pm

Demo #16



The Real-Time Expression Evaluator is nearly complete and already ready to be used.


Image
Image
These two pictures show the expressions changing as the board dimensions change.
The expression “[winmine.exe+0x5334]” gives us the width of the board, while “[winmine.exe+0x5338]” gives us the height (as printed in the list).
These are some of the most basic expressions.
The 3rd expression is created by multiplying the width and height, making the expression a bit more complicated.

And all of these values update in real time so, as the game information changes, the values will reflect those changes.



It should always be assumed that when I add a feature, there are no shortcuts or shortcomings; I’m here to add the real deal, no matter how complex.
The next shot shows something a bit more complex (and practical, unless you really want to hack Minesweeper all your life).
Image

[Project64.exe+0xD6A3C] is the game RAM pointer in Project64. This tells us where the emulated game RAM is located (shown here as being at address 3AD70000).
[[Project64.exe+0xD6A3C]+0x62988] is the player list pointer in Perfect Dark™. To find the locations of all the players in multiplayer, we have to go here. Its value is 805013F0. This value is a valid pointer in the Nintendo® 64. The upper 8 bits (80) are a type of bank, but we don’t need that when we follow the pointers through Project64, which uses its own virtual addressing system.

To follow this Nintendo® 64-format pointer, we have to mask off the top 8 bits using ([pointer] & 0x00FFFFFF)
Then the pointer will be in standard format, but since it is using the virtual mapping address system of Project64, we would then have to take that value and add the Project64 RAM pointer to it ([Project64.exe+0xD6A3C]).

The next line down does all of that, and then adds the structure offset to that, which is a pointer to something I forgot at the moment. I believe the result is a pointer to data related to that player.


The next expression (second from bottom) shows the same expression without the square brackets. This returns the address, instead of returning the value at that address (remember, [ ] means “value at that address”).


Finally, the bottom expression is the most interesting.
f[([[Project64.exe+0xD6A3C]+0x62988]&0xFFFFFF)+[Project64.exe+0xD6A3C]+0x144]

Let’s break this down.
f[([[Project64.exe+0xD6A3C]+0x62988]&0xFFFFFF)+[Project64.exe+0xD6A3C]+0x144] This gets the location of the game RAM emulated by Project64.

f[([[Project64.exe+0xD6A3C]+0x62988]&0xFFFFFF)+[Project64.exe+0xD6A3C]+0x144] This takes that location and adds 0x62988 to it, taking us to the player list pointer address. At this point, we are at the address of that list, but we have not gotten the value at that address (which will be a pointer in Nintendo® 64 format).

f[([[Project64.exe+0xD6A3C]+0x62988]&0xFFFFFF)+[Project64.exe+0xD6A3C]+0x144] Use the brackets to get the value at that address. The value is, as mentioned, a pointer in Nintendo® 64 format.

f[([[Project64.exe+0xD6A3C]+0x62988]&0xFFFFFF)+[Project64.exe+0xD6A3C]+0x144] To get that pointer into normal format, we have to perform the pointer & 0x00FFFFFF operation. Best to use parenthesis to make sure this is all evaluated as a set. This is standard in math and programming.

f[([[Project64.exe+0xD6A3C]+0x62988]&0xFFFFFF)+[Project64.exe+0xD6A3C]+0x144] After translating the pointer it becomes an offset that must be added to the emulator’s RAM pointer. Do that here.


f[([[Project64.exe+0xD6A3C]+0x62988]&0xFFFFFF)+[Project64.exe+0xD6A3C]+0x144] After doing all that we have the location of the first player in the game. The players are stored in order, one after another. By adding offset 0x144, we go to the address of the second player’s Z position.

f[([[Project64.exe+0xD6A3C]+0x62988]&0xFFFFFF)+[Project64.exe+0xD6A3C]+0x144] We went to the address of the second player’s Z position. Using [ ], we can get the value at that address, as mentioned before. But the value is stored in float form, so we add f (or F) to the opening [. This tells the parser to get the value there and decode it as a float instead of as a DWORD.
As shown in the picture, the Z location of the second player is 61.591053.



The Real-Time Expression Evaluator can be used to find and display any value in the game, no matter how many pointers are used to get to them, and no matter what kind of encoding has been applied to the pointers/values.

Current Operators:
! (not)
~ (one’s compliment)
+ (unary plus, as in +3)
- (unary minus, as in -3)

+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulo)

& (bitwise AND)
| (bitwise OR)
^ (bitwise XOR)
>> (right bitwise shift)
<< (left bitwise shift)

( ) (parenthesis, defines order of operation)
[ ] (get value at address as a DWORD)
b[ ] (get value at address as a BYTE)
w[ ] (get value at address as a WORD)
q[ ] (get value at address as a QWORD)
f[ ] (get value at address as a FLOAT)
d[ ] (get value at address as a DOUBLE)




Instructions:
Hit the + button to add the current expression to the list. When in the list, it will be evaluated in real-time.
Select expressions from the list and hit - to remove them.

Expressions are saved when the program closes and automatically reloaded upon restart, so you don’t have to type them again.

Expressions are compiled into a binary format and parsed from there, so expression evaluation is extremely fast and uses few resources. Do not worry about slowness related to text parsing; there is none.







Soon these will be added to the stored values so you can use them to calculate the addresses of your values.
For now, I decided to release this version to allow people to get a good idea of just how powerful they are.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby L. Spiro » Thu Mar 08, 2007 11:39 am

Demo #17

This should fix all known issues.
The bug related to the Same as Original Sub Search was so tricky and deeply hidden, I have no other confirmed reports of this bug happening to anyone else.

It seems it happened to me only due to the exact search settings and number of returns I happened to get that day.
In fact, I have only been able to produce this bug 3 times, all in one day, while performing one specific series of searches.


The bug was so elusive I could rarely reproduce it on purpose, and never in debug mode to actually see the code that caused the problem.



I was updating my code naming conventions and updating to std::nothrow new in the searcher and stumbled upon some code that was obviously wrong.
The location of the code matches the timing related to the Same as Original crash, and possibly explains why the search settings and number of returns have to be exact for the crash to happen.

This has been fixed, along with changing all allocation to non-exception-throwing allocators, making the entire searcher faster and more stable.




With a bug this elusive, it is impossible to say this is definitely the fix, but all arrows are pointing up, and all evidence suggests it should be the fix.




The official word for now is 100% stability, no known issues or resource leaks of any kind, in any part of the project.
The project is crystal clear, neat, organized, stable, reliable, and clean.


Please report any new issues with full descriptions and reproductability.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby Kakashi_s1 » Sat Mar 10, 2007 12:12 pm

man, spiro, all these cool things you're adding into the program and I cant use. For some reason, my game wont search for any data.

Do you want to download Legend of Ares and see what you can do with it? Or can you make an update and decrease the priority? OR maybe I should uninstall and reinstall with the lastest demo.

PS. I can search xtrap, MHS, etc. just not my game.

[EDIT] I think i got it what's wrong. The game has 3 found IDs and four UNKNOWN IDs.

with demo7, I only had one choice to choose from which is ID OFE4(4068).
With demo17, I can choose the process OFE4(4068) but no values will show. However, once I hit the ALL button, I see alot of Ares.exe processes. In the 3 found IDs, OFE4(4068) is not found, but it's one of the UNKNOWN IDs.

So I target one of the found IDs and viola, I can see all the values that I need to see. But another problem arises. I cant lock the values. Everytime I try to modify and lock, it reverts back to the original value. Do you know how this can be overcome? Or am I again choosing the wrong process ID to hack?
Kakashi_s1
Sir Hacks-A-Lot
 
Posts: 34
Joined: Wed Jan 17, 2007 4:25 pm

Postby L. Spiro » Sun Mar 11, 2007 2:28 am

There could be many factors.

Make sure the value is actually locked with a green icon by it.

Change the lock update speed if it is not locking hard enough.

Otherwise, figure out why it is being changed back and man-handle it.
You have the real-time Hex Editor and can modify values manually in there.
Then you can see if it is the game’s problem or mine.
You can also use the Disassembler/Debugger and find out what is writing to it.
Because it is a read/write breakpoint, you would normally want to use hardware, however one of the updates I added to the debugger broke the hardware read/access breakpoints, and only my current unreleased version has them working. Use software for now.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby L. Spiro » Sun Mar 11, 2007 11:41 am

Demo #18


Fixes the Group Search.
Fixes Hardware Read/Write Breakpoints.
Probably Does More Things I Forgot I Added.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby esco » Tue Mar 13, 2007 4:03 am

Hey Spiro, I've been playing with 16.... and I still RARELY have it crash when I double click a value to change it.... it seems to happen randomly. I've tried it on 2 computers, but it is MUCH more stable than before. NICE WORK!

Also I wanted to ask you for some quick help... I was messing with printf statements, and I noticed that it will print the text in the box below the scripts in the code editor. However I was wondering if there is a way to get the text to PRINT on the screen of the process itself. I'm using EPSXE and this could come in handy for me soon for those people who want to play it in full screen. :D
Esco.... the name says it all. New Yorikan for life.
User avatar
esco
NULL
 
Posts: 148
Joined: Mon Sep 18, 2006 2:25 am
Location: Florida, a.k.a. the US's version of hell!

Postby L. Spiro » Tue Mar 13, 2007 4:49 am

I have never had crashes when double-clicking items to be edited. Also the latest demo is #19.

And no it is not easily possibly to route the text to be used in the game.
You can manage it manually by getting the HDC of the process’s main window and drawing the text manually to it.
But you have to do it repeatedly and it will flicker.
And you will have to manage your own buffer, but that is not hard.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby esco » Sat Mar 17, 2007 9:05 am

L. Spiro wrote:I have never had crashes when double-clicking items to be edited. Also the latest demo is #19.

And no it is not easily possibly to route the text to be used in the game.
You can manage it manually by getting the HDC of the process’s main window and drawing the text manually to it.
But you have to do it repeatedly and it will flicker.
And you will have to manage your own buffer, but that is not hard.

L. Spiro


That doesn't sound like it will work... since I'd have no F_ing clue how to do it, lol! But thanks anyways for the help. I don't suppose you know a QUICK way of declaring variables for memory address when there is a PATTERN present.

Ex. let's say I want to declare 5 variables with these addresses:
5b6e40
5b6e42
5b6e44
5b6e46
5b6e48

There is an OBVIOUS pattern here... now I could sit there and declare them each manually the way you showed me. Which is:

extern WORD rooms = { "", 0x005b6e40 };

But is there a quicker way to do this that would help my hack run more effeciently and use less ram? I was gonna try an Array, but I don't see a
way to do this since I'm using memory addresses.

I'm REALLY concerned with this since all the scripts I have are ALREADY starting to slow the game down. I am planning on combining a lot of them for the final reason, so that an address is NOT declared twice. But any advice I can get from anywhere would be appreciated too.

P.S. this c programming class I'm takin really HAS helped me a little bit with this stuff too. :)
Esco.... the name says it all. New Yorikan for life.
User avatar
esco
NULL
 
Posts: 148
Joined: Mon Sep 18, 2006 2:25 am
Location: Florida, a.k.a. the US's version of hell!

Postby L. Spiro » Sat Mar 17, 2007 11:55 am

Ex. let's say I want to declare 5 variables with these addresses:
5b6e40
5b6e42
5b6e44
5b6e46
5b6e48

There is an OBVIOUS pattern here... now I could sit there and declare them each manually the way you showed me. Which is:

extern WORD rooms = { "", 0x005b6e40 };



extern WORD rooms[5] = { "", 0x005b6e40 };
An array of rooms, each 2 addresses apart, with one declaration line.
Note that you supplied 5 here, but it can really be any positive number, since the variables already exist in the target process. It isn’t actually creating an array, so even after you declare it as an array of 5 you could access array index 78 if you wanted.


Any variables of a similar kind that are close together can be grouped into arrays this way, even if there are other values between them.

If you have:
Code: Select all
extern DWORD dwThis = { "", 0x005b6e40 };
extern DWORD dwThat = { "", 0x005b6e50 };
extern DWORD dwThose = { "", 0x005b6e64 };
dwThis = dwThat = dwThose;

It would be faster to do this:
Code: Select all
enum {
    E_THIS,
    E_BLANK1, E_BLANK2, E_BLANK3,
    E_THAT,
    E_BLANK4, E_BLANK5, E_BLANK6, E_BLANK7,
    E_THOSE,
};
extern DWORD dwArray[1] = { "", 0x005b6e40 };
dwArray[E_THIS] = dwArray[E_THAT] = dwArray[E_THOSE];



The blank array indices skip over the data between dwThis, dwThat, and dwThose.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby esco » Sun Mar 25, 2007 8:57 am

Wow! That will DEFINATELY help it run better! Since any sprite based item has 188 entries, I can just declare an array of size 1, then just point to the corresponding memory address using that var, rather than declaring 20 or so variables to do what I need. GREAT! I do have another question about this though... since you say the addresses are 2 apart.... is there any way to make them 1 memory address apart?

I know I can just make another array for this (Ex. array[1] =5b6e40 for even values, and then array2[1] for 5b6e41 for odd values), but I just wanted to know if there is a way to change the gap between each value. Especially since later I will have something where there will be a gap of about 188 between each value I will be changing, and that can get very confusing after a while to keep track of.

P.S. I'm assuming that this technique of using ARRAYS would use a LOT less memory, and will help it run faster than just declaring a ton of variables, right? This is important to me, since I have a LOT of code as you have seen. :)
Esco.... the name says it all. New Yorikan for life.
User avatar
esco
NULL
 
Posts: 148
Joined: Mon Sep 18, 2006 2:25 am
Location: Florida, a.k.a. the US's version of hell!

Postby L. Spiro » Sun Mar 25, 2007 11:39 am

P.S. I'm assuming that this technique of using ARRAYS would use a LOT less memory than just declaring a ton of variables, right?

Each external variable consumes (9 + module-name length) bytes of local RAM.


you say the addresses are 2 apart.... is there any way to make them 1 memory address apart?

Use a BYTE array instead of a WORD array. You know this already.


Ex. array[1] =5b6e40 for even values, and then array2[1] for 5b6e41 for odd values

It wouldn’t work this way.
extern WORD e_wArray1[1] = { "", 0x5B6E3E };
extern BYTE e_wArray2[1] = { "", 0x5B6E3E };
e_wArray1[1] would be on address 0x5B6E3E + 2 = 0x5B6E40.
e_wArray2[1] would be on address 0x5B6E3E + 1 = 0x5B6E3F.



Since any sprite based item has 188 entries, I can just declare an array of size 1, then just point to the corresponding memory address using that var, rather than declaring 20 or so variables to do what I need.

If you are working with organized data structures in the game it is better to create a structure in your script that matches theirs and use that.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby esco » Sun Mar 25, 2007 1:42 pm

L. Spiro wrote:Each external variable consumes (9 + module-name length) bytes of local RAM.


Whoa... so I AM saving a bit of RAM(considering that one enemy can use 20 entries, and there can be 10 enemies in a room, it can add up veryfast)! Though I am more concerned with CPU power, since already the file I sent you with my scripts a while back, was ALREADY slowing the emulator down a bit. And I have 2.8gig cpu, and a gig of ram.

And it's's only about 25% done AT MOST! Hopefully this should speed it up a bit in the end! :D


Use a BYTE array instead of a WORD array. You know this already.


Yeah your right, I can't believe I asked this question. Mah bad. :oops:

If you are working with organized data structures in the game it is better to create a structure in your script that matches theirs and use that.


?????? Wha I have NO CLUE what this last statement means. Can you elaborate or give a quick little example?
Esco.... the name says it all. New Yorikan for life.
User avatar
esco
NULL
 
Posts: 148
Joined: Mon Sep 18, 2006 2:25 am
Location: Florida, a.k.a. the US's version of hell!

Postby L. Spiro » Sun Mar 25, 2007 3:10 pm

You do too know what it means.

Code: Select all
struct SPRITE {
    WORD wX;
    WORD wY;
    BYTE bBuffer1[32];
    WORD wRot;
    // Etc.
};

extern SPRITE e_sEntity1 = { "", 0x5B6E40 };
e_sEntity1.wRot = 90;



L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby esco » Mon Mar 26, 2007 1:06 am

L. Spiro wrote:You do too know what it means.

Code: Select all
struct SPRITE {
    WORD wX;
    WORD wY;
    BYTE bBuffer1[32];
    WORD wRot;
    // Etc.
};

extern SPRITE e_sEntity1 = { "", 0x5B6E40 };
e_sEntity1.wRot = 90;



L. Spiro


OH SHIT! Now I think I know what you mean!! Basically lets say for enemy data... I make a struct with 94 variable entries like that (188/2 for the even ones only) which I declare one at a time. Then I just use that structure to declare another variable of that structure type, and have it start at the FIRST memory address I want to use. So in essence if I combine, my scripts for enemies into 1 HUGE file, I can then just use the same structure OVER and OVER again! Rather than using a matrix, which can be harder to go back and change later right?

To give an example of what I mean (so that I make sure I am understanding you):

Code: Select all
struct ENEMIES {
    SHORT hspeed;
    SHORT vspeed;
    SHORT action1;
    BYTE actiondata;
    SHORT frametimer;
};

extern ENEMIES axearmor1 = { "", 0x62cdc0 };
extern ENEMIES axearmor2 = { "", 0x62eed0 };

//so Hspeed will equal 62cdc0, vspeed = 62cdc2, action1 = 62cdc4, actiondata= 62cdc5, frametimer = 62cdc6, for axearmor1 ....is that right?
//and for axearmor2 instead the memory addresses will be: Hspeed will equal 62eed0, vspeed = 62eed2, action1 = 62eed4, actiondata= 62eed5, frametimer = 62eed6. Am I on the right track here?

if (axearmor1.action1 == 4) axearmor1.hspeed = 512;


Is this what you mean?
Esco.... the name says it all. New Yorikan for life.
User avatar
esco
NULL
 
Posts: 148
Joined: Mon Sep 18, 2006 2:25 am
Location: Florida, a.k.a. the US's version of hell!

Postby L. Spiro » Mon Mar 26, 2007 9:38 am

No. The addresses are wrong.


Code: Select all
struct ENEMIES {          = 0x62cdc0
    SHORT hspeed;        = 0x62cdc0 + 0 = 0x62cdc0
    SHORT vspeed;        = 0x62cdc0 + 2 = 0x62cdc2
    SHORT action1;        = 0x62cdc0 + 4 = 0x62cdc4
    BYTE actiondata;  = 0x62cdc0 + 6 = 0x62cdc6
    SHORT frametimer; = 0x62cdc0 + 7 = 0x62cdc7
};



If you make a structure, you have to be careful with this.
This is the part that will trip you.
You have to correctly insert the structure members in a way that each member lands on the correct offset from the base.

If you fail to do this, it will format all hard drives in your town, maybe even your state.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Next

Return to General Related Discussions

Who is online

Users browsing this forum: No registered users and 0 guests