-
Notifications
You must be signed in to change notification settings - Fork 7
Finding D CODE (Deprecated)
Deprecated, cross-platform compatibility issue. Now, Agent use custom script instead
Intro
Most of the emulators nowaday are using Dynamic Recompiler, This is also the so called JIT (Just-In-Time compiler).
This JIT will "translate" (MIPS, ARM,...) native codes to x86_64 codes for the PC to be able to understand.
Every data block, function will be recompiled to x86_64 codes when the game start to run.
JIT'd code will reside at random places in memory (RAM, cache). Unlike exe and/or dll, they neither have concrete structures nor static addresses.
And the text hookers we have at moment don't support the randomness of the JIT.
We can hook the text hooker into the JIT engine of the emulator, but this way has a few problems.
e.g.: can't make the text hooker hook into the specific address,...
The emulator need to support this feature in order to solve the problem above.
So we need another method.
The addresses are random but the adjacent native codes of the game can create some kind of signatures
,
we can rely on these signatures
to scan memory and setting address for the text hooker.
But this method is not without caveats.
If the JIT engine change the way it generate x86_64 codes from the naitive codes (e.g. optimize, upgrade) then the signatures
will be changed accordingly.
But signatures
still work with the older version of the emulator.
Requirement:
-
Cheat Engine
: scan and monitor memory. (CheatEngine7.2_MissingSetup.rar)
If you don't like CE, use x64dbg + xFindOut -
ASM skill
: not necessary.
Video: Finding D-CODE part1; part2
Use the
AOB (array of byte)
function ofCheat Engine
.
- Search for keywords:
-
Save State
at any dialog(A)
in the game, then move to the next dialog(B)
to find the keywords of(B)
. - We can use OCR to search for keywords of
(B)
.
- Get results:
-
Load State
andFirst Scan
with the keywords at step 1. - At this moment, the game doesn't load
(B)
yet, so the number of results we get will be better (fewer) than when we search for keywords from(A)
.
(Could re-open the game andLoad State
, because whenLoad State
at(B)
->(A)
might still leave the keywords of(B)
on the memory).
Now we have ~4 results,
One of this results will be the realaddress
which the game's native codes will beread | write
at.
Let's call it'real_add'
Use the
Find out what access this address
function ofCheat Engine
.
Test each address to check what address has instruction access to(B)
.
-
Load State
to go back to dialog(A)
Select anaddress
and openFind out...
(we can tryFind out...
2addresses
simultaneously) -
Next to dialog
(B)
, if theFind out...
window show theinstructions
list then clickStop
to pause the access monitor,
if not then go back to step 1 and continue to find.
Now we have many
addresses
ofinstructions
which has access to'real_add'
.
Fewaddresses
in this list could be used to createsignature
.
The goodaddresses
for creatingsignature
is the ones only run/called when the dialog in-game change.
Can test out each instruction's
address
in theFind out...
window.
Select theaddresses
fromInstruction
which has lowCount
and try to enter it into the script.
If the script works then we can start to createsignature
andD-Code
And if the script doesn't work thenlive reload
and test out otheraddresses
from anotherInstruction
.
The length can be any, just make sure your signature matches only one result.
You can improve your signature with the wildcards.
bytecode | |
---|---|
450FB6640500 450FB6E4 4489642430 4589E4 4D896740 31C0 448B642430 4181FCEF000000 F5 9F 0F90C0 41898708010000 48836C242003 418B8708010000 9E 752E 48837C242000 B8404E1308 |
45?????????? 45?????? 44???????? 45???? 4D?????? 31?? 44???????? 41???????????? F5 9F 0F???? 41???????????? 48?????????? 41???????????? 9E 75?? 48?????????? B8404E1308 -- yuzu only (ARM address 0x08134E40 - constant) |
Final signature:
450FB6640500450FB6E444896424304589E44D89674031C0448B6424304181FCEF000000F59F0F90C04189870801000048836C242003418B87080100009E752E48837C242000B8404E1308
or (better)
45??????????45??????44????????45????4D??????31??44????????41????????????F59F0F????41????????????48??????????41????????????9E75??48??????????B8404E1308
$encoding,?align|?debounceOption|terminatedPattern,?offset|?expressions|signature
$: d-code magic char
?: optional
Decode | Read | Hook | ||||
---|---|---|---|---|---|---|
encoding | ?align|?debounceOption|terminatedPattern | ?offset|?expressions|signature | ||||
encoding | ?align | ?debounceOption | terminatedPattern | ?offset | ?expressions | signature |
Which:
-
encoding
:shift_jis
,utf-8
,utf-16le
,utf-32le
,...- TODO: allow custom preprocess (array decrypt), postprocess (string filter).
-
terminatedPattern
: string terminate pattern (it could be 1, 2, 4, 8 bytes), e.g:00
or00 00
or0D 0A
...; or fixed-size buffers, e.g: *256 (256 bytes), * (default 4096 bytes).-
align
: default is the terminatedPattern's bytes count. -
debounceOption
: typeTIMEOUT, type: l (leading), t (trailing sync), lt (leading-traling); T (trailing callback). Example.
-
-
signature
: the array of bytes to determine which position to hook.-
expressions
: by default, the script will auto-calculate the addresses it need to read from themov
instruction,
if the place to set hook is notmov
, you can set it manually. e.g:[rdx+8]+4
-
offset
: default is 0, the hook will set at the found address +0.
-
For PC games
-
signature
: can be...-
Module$signature
, e.g:- Main exe:
$EB??????????DC
- Specific dll:
target.dll$EB??????????DC
- Main exe:
-
Module$:RVA
, e.g:- Main exe:
:$1000
- Specific dll:
target.dll:$1000
- Main exe:
- Virtual address, only when target doesn't has ASLR, e.g.:
0x401000
-
For example:
-
$utf-16le,000?,450FB664????DC
:- Scan
450FB664????DC
to set hook. - Get the default address to read in-game text from
mov
instruction. - Read until
000?
(terminatedPattern
). - Decode with
utf-16le
encoding.
- Scan
-
$utf-32le,4|000000?,|rcx|EB??????????DC
:- Scan
EB??????????DC
to set hook (default offset is 0). - Get the default address to read in-game text from
rcx
register. - Read until
000000?
, padding 4 bytes afterward. - Decode with
utf-32le
encoding.
- Scan
-
$utf-8,000?,45??????????45??????44????????45????4D??????31??44????????41????????????F59F0F????41????????????48??????????41????????????9E75??48??????????B8404E1308
- Final D-Code.
-
Script setting:
globalThis._FIXED_DCODE_ = '$...';
//globalThis.decode = function(buffer) {
// return _decode(buffer);
//}
//globalThis.filters = function(s) {
// return _filters(s);
//}
require('_ExecutionWatch.js');
Good luck!
Find or share DCODE: https://docs.google.com/spreadsheets/d/14k5TBc2cAed8Fcx2fb5schlPh6Ah24dmW3dJpxvNAbc/