Skip to content

Finding D CODE (Deprecated)

0xDC00 edited this page Jul 23, 2022 · 1 revision
Deprecated, cross-platform compatibility issue. Now, Agent use custom script instead
Intro

How emulators work?

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.

Solution

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.

The steps to find the signatures to generate D-Code (dynamic code)

Requirement:

Video: Finding D-CODE part1; part2

I. Find address of an text string in memory

Use the AOB (array of byte) function of Cheat Engine.

  1. 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).
  1. Get results:
  • Load State and First 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 and Load State, because when Load State at (B) -> (A) might still leave the keywords of (B) on the memory).

AOB Scan

Now we have ~4 results,
One of this results will be the real address which the game's native codes will be read | write at.
Let's call it 'real_add'

II. Find the 'real_add'

Use the Find out what access this address function of Cheat Engine.
Test each address to check what address has instruction access to (B).

  1. Load State to go back to dialog (A)
    Select an address and open Find out... (we can try Find out... 2 addresses simultaneously)

  2. Next to dialog (B), if the Find out... window show the instructions list then click Stop to pause the access monitor,
    if not then go back to step 1 and continue to find.

Real Address

Now we have many addresses of instructions which has access to 'real_add'.
Few addresses in this list could be used to create signature.
The good addresses for creating signature is the ones only run/called when the dialog in-game change.

III. Choose the correct instruction in the list of results to find signature

Can test out each instruction's address in the Find out... window.
Select the addresses from Instruction which has low Count and try to enter it into the script.
If the script works then we can start to create signature and D-Code
And if the script doesn't work then live reload and test out other addresses from another Instruction.

Signature

Example Signature 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

D-Code structure

$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 or 00 00 or 0D 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 the mov instruction,
      if the place to set hook is not mov, 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
    • Module$:RVA, e.g:
      • Main exe: :$1000
      • Specific dll: target.dll:$1000
    • 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.
  • $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.
  • $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/