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 


first scan, scan type 'unknown initial value (hash)'

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
mgr.inz.Player
I post too much
Reputation: 222

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

PostPosted: Wed Jul 17, 2013 6:30 am    Post subject: first scan, scan type 'unknown initial value (hash)' Reply with quote

For now, first scan, scan type 'unknown initial value' works like this:
- it dumps all memory (depends on memory scan options) to temporary files.

My idea for improvement is: using FAST hash algorithm. Not CRC32.

Something like MD5 or SHA1 or even better, one of those (those are noncryptographic):
xxHash
xxHash256
MurmurHash
CityHash
BLAKE2S (cryptographic)


This scan type could be called: "unknown initial value (hash method)"
I think, 256 bytes chunk/block should be enough. After first scan, "unknown initial value (hash method)", we will see:
"Found: 947812 chunks"

instead of 242639872 addresses.


Of course next scan type will be only:
- changed
- unchanged

We took "changed" and after scan we will see "Found: 166562 chunks"

Of course, after 1st (2nd, 3rd, 4th, .....) NEXT SCAN, if found counter will be less than 39060 chunks ( about 10'000'000 addresses),
then, from now on, "NEXT SCAN" will work normally (it will save values instead of hashes), "increased, smaller, ..." will be available again.

One address (address of chunk) will convert to 256 addresses.



Of course I wanted to make something like this by using "custom type". (with implemented simple fast hash mentioned before, or cryptographic hash). When first scan or next scan have more than 39060 chunks, AA script will return 32bit hash and we can use changed/unchanged scan type. When less than 39060 chunks, AA script will return normal 32bit int value or 32bit float.


But there are some problems:

* we can not change custom type behavior, depending on current found chunks
Well, I could use something like this, inside "custom type AA":
Code:
test byte ptr [cheatengine-i386.exe+500],01
je useHash

and writeBytesLocal('cheatengine-i386.exe+500', behavior)



* there is no profit from using chunks, example:

alloc(BYTESIZE,4)
alloc(PREFEREDALIGNMENT,4)

BYTESIZE:
dd (int)64

PREFEREDALIGNMENT:
dd (int)64

Scanning should be 16 times faster, and temp files should have 1/16 weight of original (BYTESIZE 4, PREFEREDALIGNMENT 4).

It looks like CE still store entire 64byte chunk for one address, instead of final 32bit value.

Fortunately, when PREFEREDALIGNMENT is 4 and BYTESIZE is 64, CE doesn't store 60 bytes again (two addresses, in sequence, will take 68 bytes instead of 128 bytes)



Why temp files doesn't have 1/16 weight of original when PREFEREDALIGNMENT is 64 and BYTESIZE is 64 ?


* we can not change PREFEREDALIGNMENT and BYTESIZE on the fly
(maybe another writeIntegerLocal to change those parameters)

* CE still must be modified (changing chunk address to 256 normal addresses)

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

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

PostPosted: Wed Jul 17, 2013 8:25 am    Post subject: Reply with quote

Actually, unknown initial value doesn't dump it to a tempfile, but it does generate an "first scan" file if you wish to compare against it later on with compare to first scan (it's a feature but you can remove it for speed gains)

(With an unknown initial value scan, the whole memory of the game is saved in ce's memory for the first next scan)

Also, the first scan unknown initial value scans are not stored as addresses but address ranges that are used to lookup the old value in the memory, which is just the process memory in a contiguous form

The number of addresses found is an calculation based on the total memory read divided by the alignment

When you do a next scan, it will compare the memory stored in ce with the memory of the game, and if any byte doesn't match check if the new value adheres to the scan parameters.

For the first next scan hashes probably wouldn't make a difference, since to generate a hash every byte has to be read of the chunk you make a hash for, and you might as well use that time to compare it against the memory that's already stored

-
Of course, the changed/unchanged method for next next scan's might be something to look into if the value type is too big

_________________
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: 222

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

PostPosted: Wed Jul 17, 2013 11:20 am    Post subject: Reply with quote

Quote:
the whole memory of the game is saved in ce's memory for the first next scan

This is the problem. I do first scan unknown initial value, scan options *W,*X.
Game process takes (task manager) about 920MB

First scan unknown (4 bytes, align 4):

It will copy entire 920MB (ce process takes now 955MB), and "MEMORY.FIRST" file is created. First stage takes about 3-5minutes, second stage (creating file) takes about 6 minutes. It doesn't matter if I use 64bit CE or 32bit CE. Because I have only 2GB RAM.

addresses found: 242'507'776 (all memory ranges divided by alignment)
(242507776 * 4 = 970031104 which is 925MB)

What we get:
ADDRESSES.FIRST  - keeps address ranges, few KB
MEMORY.FIRST        - dump (used for "compare to first scan"), 925MB

CE process   - 955MB (more or less)
Game process - 920MB (more or less)




Now I make "unchanged" first next scan (yes, I know I should choose changed, but this is worst case scenario example):
addresses found: 238'126'698
(238126698 * 4 = 952506792 which is 908MB)

I have to wait 15 minutes.

What we get:
ADDRESSES.FIRST  - [file doesn't change]
MEMORY.FIRST        - [file doesn't change]
Addresses.TMP        - keeps addresses, 908MB
Memory.TMP            - keeps "values",  908MB

CE process - 40MB (more or less)
Game process - 920MB (more or less)


Now I make "changed" next next scan:
addresses found: 37'674

What we get:
ADDRESSES.FIRST  - [file doesn't change]
MEMORY.FIRST        - [file doesn't change]
Addresses.TMP        - keeps addresses,  147KB
Memory.TMP            - keeps "values",  147KB
and of course undo files, but those are just renamed files

CE process - 40MB (more or less)
Game process - 920MB (more or less)




Conclusion:

first scan: CPU-MEMORY, then DISK (creates copy of game process memory and stores that memory to MEMORY.FIRST - extreme memory usage)

first next scan: CPU-DISK-MEMORY (even more extreme. It uses ADDRESSES.FIRST, compares memory allocated inside CE with game memory and creates address.tmp and memory.tmp. Hard drive speed is our bottle neck)

next next scan: CPU-DISK-MEMORY (compares old memory.tmp/addresses.tmp with process memory and creates new memory.tmp/addresses.tmp, hard drive speed is our bottle neck)



And now, the same scenario, but this time with unknown initial value [hash]:
For every 256 bytes ( 64 addresses 4byte type) we create hash.

First scan unknown (4 bytes, align 4):
addresses found: 3789184 chunks

What we get:
hash for every chunk will be 32bit, so 3789184 * 4 = 15156736 = 14.45MB
CE will allocate 14.45MB for hashes, and another 14.45MB for chunk addresses.
CE process - 70MB (more or less)
Game process - 920MB (more or less)


Now I make "unchanged" first next scan:
addresses found: 3720729 chunks

What we get:
ChunkAddresses.TMP        - chunk addresses, 14.19MB
ChunkHashes.TMP            -  keeps hashes, 14.19MB

CE process - 65MB (more or less)
Game process - 920MB (more or less)


Now I make "changed" next next scan:
addresses found: 620 chunks

CE automatically will convert 620 chunk addresses to 39680 (620*64) normal addresses
addresses found: 39680

What we get:
Addresses.TMP        - keeps addresses,  155KB
Memory.TMP            - keeps "values",  155KB
and of course undo files, but those are just renamed tmp files

CE process - 40MB (more or less)
Game process - 920MB (more or less)

yes, even if only 1 address changed, CE will add other 63 addresses. We can filter them with another changed, unchanged, decreased, increased...

I know we have to read (CPU) all addresses anyway, and convert 64 addresses of type 4byte (256 bytes) to one 32bit hash. I think this is still faster than copying whole memory.



EDIT:

Is there a way to get those "first scan address ranges". Maybe I can make this inside Lua.

If I can get those ranges, I will make my own "first scan unknown", "first next scan" and "next next scan" using Lua+InjectedAssemblerScript (for making HASHES).


Edit2:

something like this:
RangesTable = returnRangesAsTable(vartype,"startAddress","stopAddress",protectionFlags ,alignmentType,"alignmentParam")

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

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

PostPosted: Wed Jul 17, 2013 12:53 pm    Post subject: Reply with quote

first next scan doesn't use ADDRESSES.FIRST at all. At most it's still waiting for the first scan to finish
When a scan is done, it's not really done. It's still saving some data away for later usage (like the first scan results) but you can already use it. If you do a next scan, it has to wait till the scan is really done (memscan.waittillreallydone) and only then start a new scan

But yes, an unchanged value will generate a huge result set and there a faster harddisk can be useful

The memory ranges thing isn't something I can export. It's too entangled

I'm not sure, but if I get time I may look into making a low memory/disk usage scan (I need to anyhow for this other ce project I work on)
--
Just wondering, is this firefox? Because what you describe is the paging file of windows constantly reading/writing as well. And due to firefox's gigantic memory leaks it sends off unused memory to the swap, but when ce scans it it gets loaded back in

_________________
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: 222

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

PostPosted: Wed Jul 17, 2013 1:05 pm    Post subject: Reply with quote

Nope, it's Metro LL. I want to find flags, and those can be everywhere, this is why I use *X*W protection flags.


"unused memory to the swap, but when ce scans it it gets loaded back in"
Metro LL too. At least under WinXP.



I think I can try make my own "unknown scans", but I can't start without returnRangesAsTable I mentioned in "second edit".

Quote:
The memory ranges thing isn't something I can export. It's too entangled

Those "ranges" are revealed bit by bit, during scan?

Hmm, this file: ADDRESSES.FIRST contains those ranges ?
Maybe you can launch "newscan" for returnRangesAsTable registered Lua function, this newscan will be immediately canceled and cleared. Is it possible?

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

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

PostPosted: Wed Jul 17, 2013 1:25 pm    Post subject: Reply with quote

addresses.first contains those ranges in this format (TMemoryregion):
http://code.google.com/p/cheat-engine/source/browse/trunk/Cheat%20Engine/CEFuncProc.pas#52

Code:

Type TMemoryRegion = record
  BaseAddress: ptrUint;
  MemorySize: qword;
  IsChild: boolean; //means there is a region before it
  startaddress: pointer; //pointer to a spot in the whole memory copy, it means the start of this region
end;

and you can destroy the memscan object after the scan (but the scan has to be fully done before it builds the first scan files, so will take a the same time as a normal unknown initial value scan)

Also, if you just want the memory regions, you might have more luck spawning the memory regions windows and read the output from the listview (get memory browser, get main menu, find view menu item, find memory regions submenu, and execute it's onClick)

_________________
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: 222

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

PostPosted: Wed Jul 17, 2013 1:45 pm    Post subject: Reply with quote

"Also, if you just want the memory regions, you might have more luck spawning the memory regions windows and read the output from the listview (get memory browser, get main menu, find view menu item, find memory regions submenu, and execute it's onClick)"

Those regions visible inside that window are used by memscan objects. Not quite?

I have to gather all regions which are:
- State ~= 'Free'
- Type == 'Image'

And just get Address and Size. Right ?

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

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

PostPosted: Wed Jul 17, 2013 1:59 pm    Post subject: Reply with quote

State=='Commit'
Protect should have at least "Write" (else it'd be useless to do an changed/unchanged memory) and you can skip 'Guard' and "Write Copy"
Type should be 'Private' and optionally 'Image' (Image means it's inside a module, static)

And then just Address and Size

--
I do understand what you mean :
Make the "Hashed region scan" (needs a better name) a completely separated scan from the normal scan routines (Do not modify the existing scan routines and probably a different gui as well)
Then when you're left with a reasonable bunch of chunks either press a button to convert these results into scanfiles that the normal memory scanner can use. (address/value groups of the wanted type), or do it automatically
And from that point do the normal scans

It 'might' be possible with lua to do that last step if you make use of the undocumented property : ScanresultFolder
Disable the foundlist, swap out the scanfiles with your own an reinitialize

It needs a memscan that has already scanned once though, but that can be a range of 00400000 to 00400001

_________________
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: 222

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

PostPosted: Wed Jul 17, 2013 3:11 pm    Post subject: This post has 1 review(s) Reply with quote

Interesting, any example? Thanks.

Now I make function, function to grab those "regions".

WIP:
Code:
function lookForWindow(timer)
  timer.Enabled = false

  for i=0,getFormCount()-1 do
    local form = getForm(i)
    if form.Name == 'FormMemoryRegions' then FormMemoryRegions = form; break end
  end

  local LV = FormMemoryRegions.findComponentByName('ListView1')

  local state = LV.Items.Item[0].SubItems[1]
  local protect = LV.Items.Item[0].SubItems[2]
  local type = LV.Items.Item[0].SubItems[3]
  local size = LV.Items.Item[0].SubItems[4]

end

function getRegions()
  local menuentry = getMemoryViewForm().findComponentByName('MemoryRegions1')
  menuentry.doClick()

  local timer = createTimer(nil,false)
  timer.Interval = 100
  timer.OnTimer = lookForWindow
  timer.Enabled = true
end

getRegions()




I tried registerFormAddNotification without luck.

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

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

PostPosted: Wed Jul 17, 2013 3:48 pm    Post subject: Reply with quote

( Address is item[x].Caption )

registerFormAddNotification example:
Code:

function FormCreateNotify(form)
  if form.getClassName()=='TFormMemoryRegions' then
    FormMemoryRegions=form
    print("Found the memory region form and stored it in FormMemoryRegions");
  end
end

FormMemoryRegions=nil
myfc=registerFormAddNotification(FormCreateNotify);


then when the doClick (after the show) the list will be filled. (don't do the handling inside FormCreateNotify as the list may not be filled in yet)

also, this works too:
Code:

getMemoryViewForm().MemoryRegions1.doClick()

_________________
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: 222

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

PostPosted: Wed Jul 17, 2013 4:21 pm    Post subject: Reply with quote

Delay is necessary....

Hash function (injected ASM) and abnormal scan routines (unknown initial hash, first, next changed, next unchanged) shouldn't be a problem.


The problem is: how to convert these results (chunk addresses) into scanfiles. And of course how exactly ScanresultFolder property works.




Code:
-- WIP

function lookForRegions(timer)
  timer.Enabled = false

  local LV = getRegionsEnv.Form.ListView1
  if LV.Items.Count == 0 then getRegionsEnv.regionsTable=nil; return end

  local regionsTable = {}

  for i=0,LV.Items.Count - 1 do
  repeat

    local state = LV.Items.Item[i].SubItems[1]
    if not state:match("Commit")  then break end  -- continue

    local type = LV.Items.Item[i].SubItems[3]
    if type:match("Mapped")       then break end  -- continue

    local protect = LV.Items.Item[i].SubItems[2]
    if     protect:match("Guard") then break end  -- continue
    if not protect:match("Read")  then break end  -- continue

    local flagW = false
    local flagX = false
    local flagC = false
    if protect:match("Write")   then flagW = true end
    if protect:match("Execute") then flagX = true end
    if protect:match("Copy")    then flagC = true end

    if getRegionsEnv.W~=nil and getRegionsEnv.W~=flagW then break end-- continue
    if getRegionsEnv.X~=nil and getRegionsEnv.X~=flagX then break end-- continue
    if getRegionsEnv.C~=nil and getRegionsEnv.C~=flagC then break end-- continue

    local size    = LV.Items.Item[i].SubItems[4]
    local address = LV.Items.Item[i].Caption

    regionsTable[#regionsTable+1] = 'address '..address..'\t'..
                                    'size '..size..'\t'..
                                    'protect '..protect..'\t'..
                                    'type '..type

  until true
  end

  print( #regionsTable )                      -- debug
  print( table.concat(regionsTable,"\r\n") )  -- debug

  getRegionsEnv.regionsTable=regionsTable
end

function findWindow(form)
  if form.ClassName=='TFormMemoryRegions' then
    getRegionsEnv.Form = form
    local timer = createTimer(nil,false)
    timer.Interval = 200
    timer.OnTimer = lookForRegions
    timer.Enabled = true
  end
end
if rfan~=nil then unregisterFormAddNotification(rfan); rfan=nil; end
rfan = registerFormAddNotification(findWindow)

function getRegions()
  getMemoryViewForm().MemoryRegions1.doClick()
end


getRegionsEnv = {}
getRegionsEnv.W = false   -- nil = doesn't matter
getRegionsEnv.X = true
getRegionsEnv.C = false
getRegionsEnv.Form = nil
getRegionsEnv.regionsTable = nil


getRegions()


~~~I'll be back in 10 - 12 hours

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

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

PostPosted: Thu Jul 18, 2013 2:14 am    Post subject: Reply with quote

Abnormal scan routines means you'll have to do your own ReadProcessMemory calls as memscan will not be useful in this case. (I really do recommend plugin dlls)

Chunk address to scanfile isn't too difficult. The addressfile is just an array of addresses (using 4 or 8 bytes/entry depending on which ce is used) and memory is an array of chunks with the varlength of the current type
So just split up the chunks into separate addresses based on if fastscan alignment is on or not and fill in the memory file with the current memory of those addresses

The addresslist starts with the text "NORMAL" followed by a 0 terminator

The ScanresultFolder property of a memscan object returns the path where it stores the temp files during it's scan, so you don't have to guess where it is

_________________
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
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine All times are GMT - 6 Hours
Page 1 of 1

 
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