Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Need help: Create new custom data type
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
Csimbi
I post too much
Reputation: 70

Joined: 14 Jul 2007
Posts: 2210

PostPosted: Sun Jul 22, 2012 8:02 pm    Post subject: Need help: Create new custom data type Reply with quote

Hi all,
I don't know the first thing about creating a custom data type, so I am seeking help.

The value consists of 5 doubles, like this (stored in the memory in this order as well):
Code:
double dVal;
double dKey1;
double dKey2;
double dChecksum;  // Irrelevant
double dZero;      // 0 or 1; 0: valid, 1:invalid
The real value is a combination of three doubles follows:
Code:
dSearchVal = dKey1 - dKey2 + dValue;


I guess it would speed up the code if there was a check that dZero is actually 0.0d before doing the math. Just a thought.

Thanks for any tips!
A complete solution would be even better Wink
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 371

Joined: 09 May 2003
Posts: 21916
Location: The netherlands

PostPosted: Mon Jul 23, 2012 5:59 am    Post subject: Reply with quote

I'm not good with fpu asm, but one method is to use an extra dll, here's the framework for that

Code:

[64-bit]
LOADLIBRARY(mytype64.dll)
[/64-bit]
[32-bit]
LOADLIBRARY(mytype32.dll)
[/32-bit]

alloc(ConvertRoutine,1024)
alloc(ConvertBackRoutine,1024)
alloc(TypeName,256)
alloc(ByteSize,4)
alloc(UsesFloat,1)

TypeName:
db 'Custom Type Name',0

ByteSize:
dd 28

UsesFloat:
db 1 //Change to 1 if this custom type should be treated as a float

//The convert routine should hold a routine that converts the data to an integer (in eax)
//function declared as: stdcall float ConvertRoutine(unsigned char *input);
//Note: Keep in mind that this routine can be called by multiple threads at the same time.
ConvertRoutine:
jmp mydllfunctionconvertroutine


//The convert back routine should hold a routine that converts the given integer back to a row of bytes (e.g when the user wats to write a new value)
//function declared as: stdcall void ConvertBackRoutine(float i, unsigned char *output);
ConvertBackRoutine:
jmp mydllfunctionconvertbackroutine


_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
mgr.inz.Player
I post too much
Reputation: 159

Joined: 07 Nov 2008
Posts: 4264
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Tue Jul 24, 2012 4:43 am    Post subject: Re: Need help: Create new custom data type This post has 2 review(s) Reply with quote

@Csimbi
I made something similar, for structure with floats. I think I can adapt it to doubles.

Stay tuned (approx. few hours).

Edit:

here:
Code:
alloc(TypeName,256)

alloc(ByteSize,4)
alloc(UsesFloat,4)
alloc(PreferedAlignment,4)

alloc(ConvertRoutine,1024)

label(SKIP)

TypeName:
db 'CustomType_for_Csimbi',0

ByteSize:
dd (int)40 // struct has 40 bytes
UsesFloat:
db 01
PreferedAlignment:
db 04

//double dValue;                                        //0x00
//double dKey1;                                         //0x08
//double dKey2;                                         //0x10
//double dChecksum;  // Irrelevant                      //0x18
//double dZero;      // 0 or 1; 0: valid, 1:invalid     //0x20

//dSearchVal = dKey1 - dKey2 + dValue;

define(dValue ,eax+00)
define(dKey1  ,eax+08)
define(dKey2  ,eax+10)
define(dZero_1,eax+20)
define(dZero_2,eax+24)

ConvertRoutine:
push ebp
mov ebp,esp
mov eax,[ebp+8] //place the address that contains the bytes into eax

cmp dword ptr [dZero_1],0
jne SKIP
cmp dword ptr [dZero_2],0
jne SKIP

finit

push eax
fld qword ptr [dKey1]
fadd qword ptr [dValue]
fsub qword ptr [dKey2]
fstp dword ptr [esp]  // store and convert to float
pop eax

//(I used qword three times because values are "double". I used dword at the end because UsesFloat is used)


pop ebp
ret 4

SKIP:
mov eax,7fffffff    // gives NaN, CE will skip it
pop ebp
ret 4



I tested it with this

Code:
[ENABLE]
globalalloc(testing,2048)

testing:
dq (double)123.0
dq (double)50.0
dq (double)40.0
dq (double)44
dq (double)1.0

dq (double)123.0
dq (double)50.0
dq (double)40.0
dq (double)44
dq (double)0.0

[DISABLE]
dealloc(testing)


Searching for value 133.0

results:
It finds second structure at "testing+28",
structure at "testing+00" is skipped.

_________________
Back to top
View user's profile Send private message MSN Messenger
mgr.inz.Player
I post too much
Reputation: 159

Joined: 07 Nov 2008
Posts: 4264
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Tue Jul 24, 2012 5:31 pm    Post subject: Reply with quote

@DB
OK, I found small problem. NaN's + Inf aren't filtered out. Above customtype script will work for "exact value" scans.
(decreased, increased,... scans are problematic).

Because you used (in memscan.pas):
(...)
    vtCustom:
    begin
      //dword config
      FoundBufferSize:=buffersize*customtype.bytesize;
      StoreResultRoutine:=GenericSaveResult;


      if customType.scriptUsesFloat then
      begin
        case scanOption of
(...)


GenericSaveResult doesn't filter NaN's Inf for customType "scriptUsesFloat := true".

So, I suggest
(...)
    vtCustom:
    begin
      //dword config
      FoundBufferSize:=buffersize*customtype.bytesize;
      StoreResultRoutine:=GenericSaveResult;


      if customType.scriptUsesFloat then
      begin
        StoreResultRoutine:=CustomScriptUsesFloatSaveResult;
        case scanOption of
(...)

new function CustomScriptUsesFloaSaveResult with isnan and IsInfinite checks.

_________________
Back to top
View user's profile Send private message MSN Messenger
Dark Byte
Site Admin
Reputation: 371

Joined: 09 May 2003
Posts: 21916
Location: The netherlands

PostPosted: Tue Jul 24, 2012 5:49 pm    Post subject: Reply with quote

Ok, i'll check that.

Also if instead of NaN you make it return 0 it won't be such a big problem. (Increased/decreased on a value that stays 0 will get filtered out. Just don't scan for the value 0, but who would do that anyhow?)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
mgr.inz.Player
I post too much
Reputation: 159

Joined: 07 Nov 2008
Posts: 4264
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Tue Jul 24, 2012 6:08 pm    Post subject: Reply with quote

OK. I've changed mov eax,7fffffff to
mov eax,0

Problem still occurs.

And what if you want to find few structures at once?
real values (combination of three)

1) scan type: "unknown initial value", value type: "CustomType_for_Csimbi"
2) do something in game, the real (combination of three doubles) values increase
3) next scan, increased value

Many +Inf , 0 and ??? in found list.

Edit:
btw. "increased value by" 1.0 gives many NaN, -Inf, +Inf, 0 and ??? as well.

mov eax,7fffffff and mov eax,0 gives almost the same thing.

Edit2:
This does the trick
Quote:
Index: C:/ce62/memscan.pas
===================================================================
--- C:/ce62/memscan.pas (wersja 1480)
+++ C:/ce62/memscan.pas (kopia robocza)

@@ -2427,7 +2427,13 @@
 {
 Generic routine for storing results. Use as last resort. E.g custom scans
 }
+var f: single;
 begin
+  if ((variableType = vtCustom) and customType.scriptUsesFloat) then
+    begin
+    f:=customType.ConvertDataToFloat(oldvalue);
+    if (isnan(f) or IsInfinite(f)) then exit;
+    end;
   //save varsize
   PPtrUintArray(CurrentAddressBuffer)[found]:=address;
   copyMemory(pointer(ptruint(CurrentFoundBuffer)+ptruint(variablesize*found)),oldvalue,variablesize);

_________________
Back to top
View user's profile Send private message MSN Messenger
Csimbi
I post too much
Reputation: 70

Joined: 14 Jul 2007
Posts: 2210

PostPosted: Tue Jul 24, 2012 9:33 pm    Post subject: Reply with quote

Hi there,
I took the script mgr.inz.Player posted and put it into CE.
I started a scan (exact value) and I got this error (see attachment).
Any thoughts?
Can it be that the code "reads over" into unallocated/inaccessible memory?



CE-ErrorOnCustomScan.png
 Description:
 Filesize:  6.53 KB
 Viewed:  23778 Time(s)

CE-ErrorOnCustomScan.png


Back to top
View user's profile Send private message
mgr.inz.Player
I post too much
Reputation: 159

Joined: 07 Nov 2008
Posts: 4264
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Wed Jul 25, 2012 2:38 am    Post subject: Reply with quote

@Csimbi
try it again, under cheatengine-i386.exe


edit:
If you want to filter out NaN and +-Inf ......

Rev: r1481
Commit log message: custom type (float) improvement
Date: Today (2 hours ago)
Author: cheatengine

http://dl.dropbox.com/u/63264075/r1481_cheatengine-i386.7z

_________________
Back to top
View user's profile Send private message MSN Messenger
Csimbi
I post too much
Reputation: 70

Joined: 14 Jul 2007
Posts: 2210

PostPosted: Wed Jul 25, 2012 4:18 pm    Post subject: Reply with quote

Wow, it works (with the new build you provided)!
Thank you very much!

I am happy to confirm that the "found out what instructions access this value" work, too.

When I try to change the value in the table, I get an error saying that "the value 'x' could not be parsed". They value can't be frozen in the table, neither - probably for the same reason.
Is there a way to tell CE how to write the value (not just read it) directly in the table (not via AA or LUA scripts)?
Back to top
View user's profile Send private message
mgr.inz.Player
I post too much
Reputation: 159

Joined: 07 Nov 2008
Posts: 4264
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Wed Jul 25, 2012 4:50 pm    Post subject: Reply with quote

Because there is "ConvertRoutine" only.
You need "ConvertBackRoutine" as well.

Edit:
Add this at the end

Code:

ConvertBackRoutine:
push ebp
mov ebp,esp

push eax
push ebx

// [ebp+8] //value
// [ebp+c] //destination address

fld dword ptr [ebp+08]

mov eax,[ebp+0c]
fadd qword ptr [dKey2]
fsub qword ptr [dKey1]
fstp qword ptr [dValue]

pop ebx
pop eax

pop ebp
ret 8


and alloc(ConvertBackRoutine,1024) at the beginning.

_________________


Last edited by mgr.inz.Player on Thu Aug 02, 2012 2:00 am; edited 3 times in total
Back to top
View user's profile Send private message MSN Messenger
Csimbi
I post too much
Reputation: 70

Joined: 14 Jul 2007
Posts: 2210

PostPosted: Wed Jul 25, 2012 5:05 pm    Post subject: Reply with quote

Should be:
dVal=User-entered-value;
dKey1=any;
dKey2=dKey1;
dChecksum=any;
dZero=0;

So, I imagine it's something like this:
Code:

ConvertBackRoutine:
fld qword ptr [eax]
fst dword ptr [dVal]
fst qword ptr [dKey1]
fstp qword ptr [dKey2]
ret

?

Edit
Added the code pieces as you said.
It's just wonderful. Works almost perfectly.
The only glitch is the case of very large numbers (see attachment).
Somehow these show up weird. It this a CE bug?



CE_LargeCustom.png
 Description:
 Filesize:  7.25 KB
 Viewed:  23636 Time(s)

CE_LargeCustom.png


Back to top
View user's profile Send private message
mgr.inz.Player
I post too much
Reputation: 159

Joined: 07 Nov 2008
Posts: 4264
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Thu Jul 26, 2012 3:16 am    Post subject: Reply with quote

You can request a "UsesDouble", ask DB Laughing

I can make this, no problem for me, only copy paste + few modifications.

_________________
Back to top
View user's profile Send private message MSN Messenger
Dark Byte
Site Admin
Reputation: 371

Joined: 09 May 2003
Posts: 21916
Location: The netherlands

PostPosted: Thu Jul 26, 2012 7:10 am    Post subject: Reply with quote

It's not because it's a double or float

This is a parsing problem (no value should begin with a 0)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
mgr.inz.Player
I post too much
Reputation: 159

Joined: 07 Nov 2008
Posts: 4264
Location: W kraju nad Wisla. UTC+01:00

PostPosted: Thu Jul 26, 2012 1:06 pm    Post subject: Reply with quote

I've just added "usesdouble".
Code:
alloc(UsesDouble,4)

UsesDouble:
db 01


Changes:
http://paste2.org/p/2083785 (mirror)
http://paste2.org/p/2083883 (DefineNewCustomType) (mirror)

Binary file cheatengine-i386 + txt file with convert routine scripts:
https://dl.dropbox.com/u/63264075/r1481_%2B%2BusesDouble_cheatengine-i386.7z

Of course, it breaks backward compatibility.
For old ConvertRoutine scripts, it's better to add xor edx,edx at the beginning.
For old ConvertBackRoutine scripts, we have to change [ebp+c] to [ebp+10], and "ret 8" to "ret c"


##############
##############

For 32bit (didn't tested 64bit)

- ConvertRoutine - output registers: eax and edx

Ex.
ConvertRoutine:
push ebp
mov ebp,esp
xor edx,edx
(...)

//storing double value
sub esp,8
fstp qword ptr [esp]
pop eax
pop edx

// for example: eax=00000000 and edx=402E0000 gives 15.0 double

pop ebp
ret 4
(...)





- ConvertBackRoutine, now it is like this:
[ebp+8] contains dword(integer, single) or qword(8byte, double)
[ebp+10] - keeps address of destination

##############
##############



And I can use 999999999999999 custom value. With key1 = 50 and key2 = 40,
dValue is 999999999999989.

So without parsing problems.[/url]

_________________


Last edited by mgr.inz.Player on Fri Jul 27, 2012 6:05 am; edited 2 times in total
Back to top
View user's profile Send private message MSN Messenger
Csimbi
I post too much
Reputation: 70

Joined: 14 Jul 2007
Posts: 2210

PostPosted: Thu Jul 26, 2012 6:54 pm    Post subject: Reply with quote

Works perfectly (both the data type and the newly compiled binary).
I'll check with 64bit version once a new build is available.
Well, what can I say? Hats off!

Do you think DB will adopt it in the next release?

One question regarding the old and the new type definition.
In the old one, there was a 'push eax' after finit and before the float artithmetics, as well as a 'pop eax' after the value has been stored.
In the new one, the initial 'push eax' is gone.
I do not understand why. Could you explain?

Thank you.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites