New Version Adaptation

Please follow the guidelines to find the offset values if you wish to support a new WMPF version on your own.

Also, PR welcome!

Prerequisites

Windows

You need to locate the folder which contains WeChatAppEx.exe, for newer versions, it will be something like

%appdata%\Tencent\xwechat\xplugin\Plugins\RadiumWMPF\19339\extracted\runtime

where the 19339 indicates the version number.

Use IDA to open flue.dll inside this folder (for much older versions, open WeChatAppEx.exe)

Linux

Depending on your distribution's packaging policy, the path may vary.

readlink /proc/$(pidof WeChatAppEx | awk '{print $1}')/exe

Analyze WeChatAppEx using IDA.

Warning

Do not continue with any actions until the indicator in the lower-left corner of IDA displays AU: idle.

LoadStartHookOffset

Linux (>=25665), Windows (>=18891)

Please search OnLoadStart (camel-case) and find the x-ref function that references a string contains applet_index_container.cc. Possibly sub_18xxxxxxx+E6

OnLoadStartHook.Extra.1

If you cannot find something similar to the picture below, and you can only see something like .rdata:000000018AB7A3E4 db 4Fh ; O , this means the loading is not complete, please wait.

OnLoadStartHook.Extra.2

To show the Pseudocode like below, press F5

OnLoadStartHook.Extra.3

If you found sub_1825B50C0 (as shown in the above example) matches the pattern in the picture above, then you can fill in

{
    "Version": xxx,
    "LoadStartHookOffset": "0x25B50C0",
}

Scroll down to the bottom of the pseudocode of this function and you will find something like

(version 19339 example)

 if ( (_BYTE)a2 )
    result = sub_182B02350(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 1376LL), *(_QWORD *)(*(_QWORD *)(a1 + 80) + 56LL));
  if ( ((unsigned __int64)v19 ^ v27) != _security_cookie )
  {
    ((void (*)(void))unk_184AD7B40)();
    __debugbreak();
  }
  return result;

We are interested in functions that are executed only when a2 is true, so please go to sub_182B02350.

You will find something like

result = *(_QWORD *)(a1 + 8);
  if ( *(_DWORD *)(*(_QWORD *)(*(_QWORD *)(result + 1312) + 16LL) + 456LL) != 1101 && *(_BYTE *)(a1 + 41) != 1 )
    goto LABEL_32;
  v34 = 0xAAAAAAAAAAAAAAAAuLL;
  ws:__localhost:9421_1 = 0;
  v30 = 0;
  v31 = 0;
  memset(v33, 0, sizeof(v33));
  v32 = v33;
  ws:__localhost:9421 = (char *)&ws:__localhost:9421_1;

The magic number 1101 is what we need. We need to tell the script how to access 1101 through multiple layers of pointer offsets and dereferencing. Please refer to the code in hook.js:

const miniappConfigPtr = a1
    .add(sceneOffsets[0])
    .readPointer()
    .add(sceneOffsets[1])
    .readPointer();
const miniappScenePtr = miniappConfigPtr
    .add(sceneOffsets[2])
    .readPointer()
    .add(sceneOffsets[3])
    .readPointer()
    .add(sceneOffsets[4])
    .readPointer()
    .add(sceneOffsets[5]);

Based on the pattern of the first argument passed to sub_182B02350, the result, and the if statement block, overall (*(_QWORD *)(a1 + 56) + 1376LL) -> result = *(_QWORD *)(a1 + 8); -> (*(_QWORD *)(*(_QWORD *)(result + 1312) + 16LL) + 456LL), the answer is:

"SceneOffsets": [56, 1376, 8, 1312, 16, 456]

Linux (>=14910), Windows (>=14199) [Old Version]

Locate the AppletIndexContainer::OnLoadStart function by searching [Perf] AppletIndexContainer::OnLoadStart in strings.

OnLoadStartHook.1

Hit x, the only x-ref function address is the offset.

OnLoadStartHook.2

How to find SceneOffsets? Please refer to the section above.

Note

Also, check the struct offset in these two marked functions. These offsets are being used in the onLoadStartHook function in frida/hook.js

OnLoadStartHook.3

CDPFilterHookOffset

Locate the filter by searching SendToClientFilter in strings.

CDPFilterHook.1

Hit x, go to the only function that references this string.

CDPFilterHook.2

The hook target function sub_1824839E0 is the very first function called in the x-refed function sub_181DB82D0.

CDPFilterHook.3

"CDPFilterHookOffset": "0x24839E0",

Save the config

Save addresses.xxxxx.json in frida/config with the params you found above where xxxxx is the new version

{
    "Version": xxxxx,
    "LoadStartHookOffset": "0x25B5DD0",
    "CDPFilterHookOffset": "0x301B3C0",
    "SceneOffsets": [1376, 1312, 456]
}

(Legacy) ResourceCachePolicyHookOffset

We don't need this in the latest version

Not sure if this function affects the sources shown in the devtools, keep hooking this just in case.

Locate the resource cache policy function by searching WAPCAdapterAppIndex.js in strings, select the second search result.

ResourceCacheHook.1

Hit x, the only function that references this string is the target function.

ResourceCacheHook.2