Simple analysis of wasm md5 of a website

Target website:aHR0cHM6Ly93d3cuaXFpeWkuY29tL3ZfMXIxb2JoanRpNTguaHRtbA==

Target parameters: & amp;vf=

1. Deduction code

Next xhr breakpoint

Go back to the stack and find that the core part is in mmc. Refresh the next breakpoint and follow it.

The incoming parameter is the link with the beginning and end removed, and the returned string is 32 characters in length.

Following along, it looks like a simple webpack

(window.iqiyiPlayerJSONPCallback = window.iqiyiPlayerJSONPCallback || []).push([[1], {
    1089: function(module, exports, __webpack_require__) {
    .............
    },
    576: function(x, a, e) {
        var i;
        i = function(x, a, i) {
            var r = e(1089)
              , c = null;
            i.exports = {
                setEngine: function(x) {
                    c = x
                },
                mmcd: r.mmcd,
                mmc: function() {
                    var x = c & amp; & amp; c.sbtr;
                    x & amp; & amp; x.authkeyInvoking();
                    var a = r.mmc.apply(r, arguments);
                    return x & amp; & amp; x.authkeyInvoked(),
                    a
                }
            }
        }
    }
}]);

The key function is the mmc in 1089. Just download it directly because it does not depend on other files. Simply run it.

The result is different, which means that the environment is probably detected and the V God plug-in is directly used.

Plug-in address: https://github.com/cilame/v_jstools

Checked something simple

Click to generate a temporary environment and copy it to the beginning of the file

Modify the code according to the error report

The test results are completely consistent

Algorithm restoration

The first is a simple ob confusion, which can be restored by just finding an open source source.

Then delete the false branch. I used the Boss Cai plug-in.

Then delete the useless code and find the aunt

It can be vaguely seen from the restored code that it is wasm, but there is no wasm file. It is directly compiled into asm.js

Usually the simplest command is

emcc main.cpp -s WASM=1 -o main.js

If you want not to output wasm, but convert it to asm.js. Change WASM=1 to WASM=0

In addition, it also changes asynchronous loading to synchronous -s WASM_ASYNC_COMPILATION=0;

If it is loaded asynchronously, an error will be reported if run directly.

The most common error is

TypeError: Cannot read properties of undefined (reading ‘apply’)

The main reason is that asynchronous loading of asm does not assign a value, that is, the c exported function and js have not completed the interaction.

Since it is wasm, the environment detection is probably not in wasm, but in the import function. The detections encountered so far include directly importing the detection function, and importing eval. There are some detection codes in wasm. In addition, due to Go comes with the particularity of js, which gives people the feeling that the environment can be obtained directly. In fact, the interaction is through js.

The target website belongs to the first import function

I imported a lot of functions and analyzed them one by one and found that as long as au returns 6, it will be fine.

function aU() {
    return 6
}

The test is the same as the website, the basic preparations are completed

The return value is 32 bits and is probably md5. Search for the keyword.

Then there is no more

Restoration is impossible, not even in this life

I don’t see any magic changes from the initialized values. Find a standard md5, which has obvious characteristics. It loops for 16* rounds. Print out each case and simply draw a picture.

Print the ones that appear 16 times

import numpy as np
from matplotlib import pyplot as plt
from collections import Counter
from t import data
counts = Counter(data)
valid_data_points = {key for key, value in counts.items() if value == 16}
filtered_data = np.array([point for point in data if point in valid_data_points])
plt.plot(filtered_data)
plt.show()

Obviously there are 4 cycles of 16

101,80,25,-117,-98,96,88,17,

These are the core parts of the first round

101

 case 101: {
                                v = $x & amp; ~Rx | Qx & amp; Rx,
                                Ex = sa + -1 | 0,
                                s = 80,
                                Ex = Ex >> 2,
                                f = v,
                                ta = na,
                                v = (v + (Ux & amp; -2) & amp; -2 | Ux & amp; 1) + (v & amp; 1) | 0,
                                g = aa + ((ia | 0) % 16 | 0) | 0;
                            break
                        }

It corresponds to

(b & amp; c) | ((~b) & amp; d) and safe_add(a, q)

 case 80: {

                                s = sa + 32 | 0,
                                    s = (g | 0) > (s >> 2 | 0) ? 36 : 25;
                                break
                            }
                       case 25: {
                            s = (g | 0) > (Tx | 0) ? 136 : 139;
                            break
                        }
                       case -117: {
                                s = (g | 0) == (Tx | 0) ? 166 : 158;
                                break
                            }
                      case -98: {
                                s = (g | 0) > (Tx + 1 | 0) ? 83 : 96;}
                      case 96: {
                                s = 88,
                                    f = c[G + (g << 2) >> 2] | 0;
                                break
                            }

Looks useless

 case 88: {
                            Ex = ca + (ia << 3) | 0,
                                g = f >> 1,
                                g = _i64Add(c[Ex >> 2] | 0, c[Ex + 4 >> 2] | 0, _bitshift64Shl(g | 0, ((g | 0) < 0) << 31 >> 31 | 0, 1) | 0, w() | 0) | 0,
                            w() | 0,
                                g = (f & 1) + g | 0,
                                Ex = (g + (v & amp; -2) & amp; -2 | v & amp; 1) + (g & amp; 1) | 0,
                                f = ((ia | 0) % 4 | 0) * 5 | 0,
                                ta = f + 7 | 0,
                                f = 25 - f | 0,
                                f = Ex << ta | (f ? Ex >>> f : Ex),
                                s = 17,
                                Vx = $x,
                                Fx = (f + (Rx & amp; -2) & amp; -2 | Rx & amp; 1) + (f & amp; 1) | 0,
                                _x = Rx,
                                xa = Qx,
                                ra = ia + 1 | 0,
                                ma = ka;
                            break
                        }

88 is the core. It doesn’t matter if you don’t understand it. f is the encrypted data. Save it and run it.

Add a log point and save the data

from Crypto.Util.number import long_to_bytes
d = [1935762479, 1819557736, ''']
datas = b""
for i in d:
    datas + = long_to_bytes(i)[::-1]
print(datas)

Remove the padding and convert it into a string. Try it on any online website. It shows that you just added salt, but the addition is a little outrageous.

Summary

In general, it is relatively not difficult. It is a little simpler than Xun’s vmp plus wasm. There is environmental monitoring, but not much. If there is confusion, it is equivalent to none (Boss Cai yyds). The main reason is that the control flow is annoying. I have taken a trick here. Guys, just restore it

In addition, the app and TV terminals should use the same set of codes to restore them basically the same. Trace code, find the location to add data, and take it out. However, the same src on the TV terminal may have two salts, mainly because qd_v is different. .