Principle Analysis of Decompilation of Confused Files in JS Invoice Verification Platform


Principle Analysis of JS Confusion File Decompilation for Invoice Verification Platform Invoice Verification Platform, because this Most JS for Invoice Verification Platform are Passed If obfuscator encryption confusion has been handled, it is more appropriate for me to practice. This article only analyses The obfuscator obfuscates the principle, method and procedure of decompiling, which should be an attempt at static analysis without discussing dynamic debugging analysis.

Characteristics and several formats of obfuscator confusion.

In order to make the process of analysis clear to the reader, several js example files are mainly exemplified. eab23.js, validate.js is a type. eaPqe3.js, VM649.js belongs to another type,

Before reading this article, please note the following instructions:

1. This paper mainly uses eab23.js and eaPqe3. The variable name in JS is analyzed and explained, otherwise, it will be difficult to explain by text only.
2. This article is a static decompiled JS file. When replacing the decompiled JS file and loading it into the website again, it will make an error. Check the reason: there may be a problem with JS syntax, I am not familiar with JS syntax, so I am not modifying the decompiled JS file for the sake of JS syntax problems.
3. I use EditPlus text editing software to convert js files in UTF8-> ANSI or ANSI-> UTF8 format.
4. Before using this method, save the JS file in ANSI encoding format. UTF8 decompilation may cause errors. After successful decompilation of js, convert it to UTF8 format using EditPlus.
5. This method is applicable: unformatted (beautified) js files. If your js have been formatted (beautified), please process it as unformatted (beautified) js file first, decompiled file, format (beautified) operation for easy reading.

1. Features

First look at eab23. The header of the JS file is a defined large array, which looks like this: (Not the header of this style, not for this article)

var _0x4d2a = ['A8kXwSouyG', 'i2zWzg0', 'W6Smpta', 'jmoCyNb0', 'amkyBSoCW5y', 'W47dTLGTW4JcRNi', 'i3L6Bv91BNvZzv9PBwC', 'pYZdOsG', 'W4bvhtFdRXFcQGa', 'W67dRCojoG', 'mYldOsVdPG', 'rK9Hy0S', 'WORcPmkTW7y', ... ... , 'EgnNC2i', 'W4mboWug', 'WPbecc0', 'CCo7W5/cLa', 'z2v0vgLTzq'];
var _0x5e21 = function(_0x4d2ad2, _0x5e214d) {
    _0x4d2ad2 = _0x4d2ad2 - 0x0;

Look at eaPqe3 again. The header of the JS file is a defined large array, which looks like this: (Not the header of this style, not for this article)

var _0xc03f = ['YnRuLXBpbmsgYnRuLXdoaXRl', 'd2hpdGU=', 'bm8tc2tpbiBza2luLTEgc2tpbi0yIHNraW4tMw==', 'YnRuLXByaW1hcnkgYnRuLXdoaXRl', 'c2tpbg==', 'bm8tc2tpbg==', 'c2tpbi0x', 'MnwxfDB8NHwz', 'LmJ0bg==', ... ... ... , 'YnRuLXN1Y2Nlc3M=', 'YnRuLWluZm8=', 'YnRuLXdhcm5pbmc=', 'YnRuLWRhbmdlcg==', 'bm8tYm9yZGVyIG1hcmdpbi0x', 'LnNpZGViYXItc2hvcnRjdXRzIC5idG4=']; (function(_0x4cd309, _0x19a697) {
    var _0x4b7cf2 = function(_0x341b9a) {
        while (--_0x341b9a) {
            _0x4cd309['push'](_0x4cd309['shift']());
        }
    };

With the head of this style, it's almost certain that obfuscator is confused.

At decompile time, this variable_ 0x4d2a or _ 0xc03f is defined as: ABC is a large array,

Load this large array data correctly:

eab23.js: Defined array_ 0x4d2a is the array you can use.

eaPqe3.js: Defined array_ 0xc03f is computed as an array that can be used normally through the following functions.

(function(_0x4cd309, _0x19a697) {  ... ... ...     _0x328575(); } (_0xc03f, 0x114));

2. Categorize Several Encryption Forms

According to large array, end]; Different types of encryption can be determined. In total, two types and four encryption functions can be summarized.

  1. Type One

eab23.js:

... , 'EgnNC2i', 'W4mboWug', 'WPbecc0', 'CCo7W5/cLa', 'z2v0vgLTzq'];
var _0x5e21 = function(_0x4d2ad2, _0x5e214d) {
    _0x4d2ad2 = _0x4d2ad2 - 0x0;
  1. Type Two

eaPqe3.js:

 ... , 'YnRuLXN1Y2Nlc3M=', 'YnRuLWluZm8=', 'YnRuLXdhcm5pbmc=', 'YnRuLWRhbmdlcg==', 'bm8tYm9yZGVyIG1hcmdpbi0x', 'LnNpZGViYXItc2hvcnRjdXRzIC5idG4=']; (function(_0x4cd309, _0x19a697) {
    var _0x4b7cf2 = function(_0x341b9a) {
        while (--_0x341b9a) {
            _0x4cd309['push'](_0x4cd309['shift']());
        }
    };

The difference between the two above is that one is closely followed by var and the other is closely followed by function.

First analyze Type 2, why do you analyze Type 2 first, because I started with Type 2 when I actually decompiled each js file, and found Type 1, so I started with Type 2.

3. Type II Analysis

EaPqe3. There are many similar things in the JS file:

'uMpwO': _0x4a4a('0x12'),
'Tgkgp': _0x4a4a('0x13'),
'jfBvM': function(_0x140b95, _0x146867) {
    return _0x140b95(_0x146867);
},
'buukD': _0x4a4a('0x14'),
'DHwRy': function(_0x1ec21f, _0xf21777) {
    return _0x1ec21f + _0xf21777;
},

VM649. There are many similar things in the JS file:

     'BkoQV': _0x3d8c('0x5', '*#dB'),
    'RZESQ': _0x3d8c('0x6', 'x5j6'),
    'KIBiL': _0x3d8c('0x7', 'eHOs'),
    'CqoPQ': function(_0x34bb7a, _0x101b41) {
        return _0x34bb7a + _0x101b41;
    },
    'LLFZo': function(_0x48b5cf, _0x152e42) {
        return _0x48b5cf == _0x152e42;
    },

eaPqe3.js and VM649. The difference between JS is _ 0x4a4a and _ The 0x3d8c parameters are one and two, where the decryption algorithms differ when decompiling is involved.

At decompile time, this variable_ 0x4a4a or _ 0x3d8c is defined as: CDE

_ Decryption algorithm for 0x4a4a, in eaPqe3. In js, is a function

var _0x4a4a = function(_0x130e4f, _0x2a0ae8) {
    _0x130e4f = _0x130e4f - 0x0;
... ... ...

_ Decryption algorithm for 0x3d8c, in VM649. In js, is a function

var _0x3d8c = function(_0x17ddb8, _0x230eed) {
    _0x17ddb8 = _0x17ddb8 - 0x0;
... ... ...

There is a slight difference between the two algorithms, _ 0x3d8c decryption algorithm ratio_ There are many decryption algorithms for 0x4a4a

        for (var _0x4dde59 = 0x0; _0x4dde59 < 0x100; _0x4dde59++) {
            _0xa3b65e[_0x4dde59] = _0x4dde59;
        }
        for (_0x4dde59 = 0x0; _0x4dde59 < 0x100; _0x4dde59++) {
            _0x190871 = (_0x190871 + _0xa3b65e[_0x4dde59] + _0x1310de['charCodeAt'](_0x4dde59 % _0x1310de['length'])) % 0x100;
            _0x2884aa = _0xa3b65e[_0x4dde59];
            _0xa3b65e[_0x4dde59] = _0xa3b65e[_0x190871];
            _0xa3b65e[_0x190871] = _0x2884aa;
        }
        _0x4dde59 = 0x0;
        _0x190871 = 0x0;
        for (var _0x1da148 = 0x0; _0x1da148 < _0x4ae65f['length']; _0x1da148++) {
            _0x4dde59 = (_0x4dde59 + 0x1) % 0x100;
            _0x190871 = (_0x190871 + _0xa3b65e[_0x4dde59]) % 0x100;
            _0x2884aa = _0xa3b65e[_0x4dde59];
            _0xa3b65e[_0x4dde59] = _0xa3b65e[_0x190871];
            _0xa3b65e[_0x190871] = _0x2884aa;
            _0x520f67 += String['fromCharCode'](_0x4ae65f['charCodeAt'](_0x1da148) ^ _0xa3b65e[(_0xa3b65e[_0x4dde59] + _0xa3b65e[_0x190871]) % 0x100]);
        }
        return _0x520f67;

This part.

After decryption,

eaPqe3.js file, becomes:

    'uMpwO': 'function *\\( *\\)',
    'Tgkgp': '\\+\\+ *(?:_0x(?:[a-f0-9]){4,6}|(?:\\b|\\d)[a-z0-9]{1,4}(?:\\b|\\d))',
    'jfBvM': function(_0x140b95, _0x146867) {
        return _0x140b95(_0x146867);
    },
    'buukD': 'init',
    'DHwRy': function(_0x1ec21f, _0xf21777) {
        return _0x1ec21f + _0xf21777;
    },

VM649.js file, becomes:

    'BkoQV': 'vOTPz',
    'RZESQ': '1|3|6|4|5|2|0',
    'KIBiL': '7|9|13|5|8|0|14|3|11|1|4|10|12|6|2',
    'CqoPQ': function(_0x34bb7a, _0x101b41) {
        return _0x34bb7a + _0x101b41;
    },
    'LLFZo': function(_0x48b5cf, _0x152e42) {
        return _0x48b5cf == _0x152e42;
    },

At decompile time, this variable_ 0x4a4a or _ The restore of 0x3d8c belongs to the CDE decryption replacement process.

The determination of the decompile variable EFG;

eaPqe3.js file

var _0x435762 = {
        'QPfhe': _0x4a4a('0x2'),
        'lZKCQ': _0x4a4a('0x3'),
        'fTmMu': _0x4a4a('0x4'),
        'yBOsQ': _0x4a4a('0x5'),
        'QuKgT': _0x4a4a('0x6'),
        'pjvTz': _0x4a4a('0x7'),
        'XsKTp': _0x4a4a('0x8'),
        'ZJHnU': function(_0x2b15c4, _0x420291) {
            return _0x2b15c4 in _0x420291;
        },
        'DPxyT': _0x4a4a('0x9'),
... ... ...

VM649.js file

var _0x23666d = {
        'Qhafz': function(_0x3e4d7e, _0x34ba06) {
            return _0x3e4d7e !== _0x34ba06;
        },
        'McUzn': _0x3d8c('0x0', '9Vq0'),
        'gNHuo': 'rFroG<;|t<bt_D=8@D4_',
        'ewfdW': _0x3d8c('0x1', 'iViv'),
        'kNblh': _0x3d8c('0x2', '9xe^'),
        'ScTiz': function(_0x57523b, _0x41c82d) {
            return _0x57523b + _0x41c82d;
        },
        'yHmhG': _0x3d8c('0x3', '*#dB'),
        'npeUT': 'KPTMk',
        'doQID': '7|1|5|2|6|8|0|3|4',
        'IOpzk': function(_0x54229b, _0x54a0f1) {
            return _0x54229b !== _0x54a0f1;
        },
... ... ...

This variable_ 0x435762 and _ 0x23666d is the decompile variable EFG

EFG formulaization and calculation of function parameters There are generally two types of EFG formulaization, one is a constant and the other is a function formula.

Will:

'buukD': 'init',
'DHwRy': function(_0x1ec21f, _0xf21777) {
    return _0x1ec21f + _0xf21777;
},

Regular:

buukD = 'init'
DHwRy = _0x1ec21f + _0xf21777

That's it.

eaPqe3.js file

      ace[_0x4a4a('0x9')][_0x435762[_0x4a4a('0x37')]] = ace[_0x4a4a('0x9')][_0x435762[_0x4a4a('0x38')]] || ace[_0x4a4a('0x9')][_0x435762[_0x4a4a('0x39')]];

After replacement

       ace['vars']['non_auto_fixed'] = ace['vars']['android'] || ace['vars']['ios_safari'];

VM649.js file

        if (_0x23666d[_0x3d8c('0xea', 'xXyQ')](_0x23666d[_0x3d8c('0xeb', 'f])s')], _0x23666d[_0x3d8c('0xec', 'Y(()')])) {

After replacement

        if ('hWLpV' === 'hWLpV') {

The decompilation of this js file is almost complete.

4. Type-One Analysis

Eab23. There are many similar things in the JS file:

var _0x529034 = function(_0x5e14f6, _0x57ca28, _0x3e86a7, _0x840509, _0xed3c8) {
    return _0x41fe(_0x840509 - -0x2a0, _0x57ca28);
};
var _0x5b09eb = function(_0x11aaba, _0xd13acb, _0x136ee0, _0x1117f6, _0xb199c5) {
    return _0x41fe(_0x1117f6 - -0x2a0, _0xd13acb);
};
var _0x4fdc5c = function(_0x1f407e, _0x434aad, _0xc703f, _0x2949dc, _0x105708) {
    return _0x41fe(_0x2949dc - -0x2a0, _0x434aad);
};
var _0x43e376 = function(_0x414ff3, _0x1b482d, _0x2ea534, _0x59f6ba, _0x2c242b) {
    return _0x41fe(_0x59f6ba - -0x2a0, _0x1b482d);
};

Validate. There are many similar things in the JS file:

var _0x59b365 = function(_0x2e8c3d, _0x5f4d89, _0x4274ee, _0x4755bd, _0x1fdebd) {
    return _0x2edd(_0x2e8c3d - -0x1c9, _0x5f4d89);
};
var _0x145334 = function(_0x522d00, _0x40ed98, _0x1d37ad, _0x382dd0, _0x5373f5) {
    return _0x1355(_0x522d00 - -0x1c9, _0x40ed98);
};
var _0x540d8c = function(_0x494c38, _0x1b5d36, _0x1ccd46, _0x3c5c10, _0x5c4f79) {
    return _0x1355(_0x494c38 - -0x1c9, _0x1b5d36);
};
var _0x3285ed = function(_0x9ff47b, _0x323bd7, _0x31fff6, _0x376f73, _0x3d4f26) {
    return _0x1355(_0x9ff47b - -0x1c9, _0x323bd7);
};

eab23.js and validate. The difference between JS is -0x2a0 and -0x1c9.

And _ 0x41fe,_ 0x2edd,_ 0x1355 involves two decryption functions.

eab23.js file

var _0x5e21 = function(_0x4d2ad2, _0x5e214d) {
    _0x4d2ad2 = _0x4d2ad2 - 0x0;
... ... ...
var _0x41fe = function(_0x4d2ad2, _0x5e214d) {
    _0x4d2ad2 = _0x4d2ad2 - 0x0;
... ... ...

validate.js file

var _0x2edd = function(_0x35ac23, _0x2edd1b) {
    _0x35ac23 = _0x35ac23 - 0x0;
... ... ...
var _0x1355 = function(_0x35ac23, _0x2edd1b) {
    _0x35ac23 = _0x35ac23 - 0x0;
... ... ...

This variable_ 0x5e21 and _ 0x2edd decompile definition variable CDE1
This variable_ 0x41fe and _ 0x1355 Decompilation Definition Variable CDE2

_ 0x59b365, _ 0x145334, _ 0x59b365, etc. is defined in Decompilation as GHI

GHI also requires formulaization and calculation of function parameters Only one is a function formula.

For example:

  var _0x59b365 = function(_0x2e8c3d, _0x5f4d89, _0x4274ee, _0x4755bd, _0x1fdebd) {
        return _0x2edd(_0x2e8c3d - -0x1c9, _0x5f4d89);

Processing into

_0x59b365 = _0x2edd(_0x2e8c3d - -0x1c9, _0x5f4d89)

Unlike the second type, replace _here first 0x59b365 GHI variable, and finally, calculate _ 0x2edd CDE1 or CDE2 function.

eab23.js file

   if (yzmWait == 0x0) {
        $(_0x542286( - 0x29f, -0x26e, -0x29a, -0x29a, -0x2a3))[_0x529034( - 0x2b7, '0ING', -0x27d, -0x299, -0x2de)]();
        $(_0x529034( - 0x2c2, '8@t@', -0x2d5, -0x298, -0x27a))[_0x4fdc5c( - 0x260, 'M!xk', -0x296, -0x297, -0x2c1)]();
        yzmWait = 0x3c;

After replacement

if (yzmWait == 0x0) {
    $('#yzm_unuse_img')['hide']();
    $('#yzm_img')['show']();
    yzmWait = 0x3c;

validate.js file

var _0x236b0b;
var _0x2d9f7a = new Date();
var _0xb2ea2 = _0x2d9f7a[_0x569190( - 0x2ce, -0x246, -0x262, -0x24d, -0x24f)]();
var _0x640a43 = _0xb2ea2[_0x524f06( - 0x1f4, -0x23d, '53V7', -0x20d, -0x24e)]();
var _0x3ff9b5 = _0x640a43[_0xd32495( - 0x218, -0x1d6, '@lGP', -0x2bf, -0x24d)](0x2);

After replacement

var _0x236b0b;
var _0x2d9f7a = new Date();
var _0xb2ea2 = _0x2d9f7a['getFullYear']();
var _0x640a43 = _0xb2ea2['toString']();
var _0x3ff9b5 = _0x640a43['substring'](0x2);

The decompilation of this js file is almost complete.

V. Summary

Points to Note

  1. For bracketed strings, be aware that if brackets are not considered, errors will occur.
  2. After formulaization of EFG, the splitting of parameters is a problem, mainly the pairing of parentheses.
  3. The decompiled js are not formatted (beautified), and the superfluous replaced code is not deleted.
  4. In this paper, only js of invoice checking platform are analyzed for example, and no other js have been tested.
  5. The open source code for this analysis is written in delphi. Can only be compiled under delphi10, delphi7 because, in js, return decodeURIComponent (_0x4828e5); The corresponding function in delphi7 has problems, but delphi10 has no problems.
  6. The decompiled js source code in this paper is suitable for algorithmic analysis of the algorithm in order to facilitate porting to other programming languages.

In delphi source

 procedure TDeObJs.AutoDeObJsCodeFile();
var
    strDeJsFile: string;
begin
    ReadJsFile(FJsFileName);
    FABC := ABC_GetABC();
    Log.i('ABC: ' + FABC);
    if not string.IsNullOrEmpty(FABC) then
    begin
        ABC_SetListData();
        if FCryptType = 1 then
        begin
            FCDE := CDE_GetCDE();
            Log.i('CDE: ' + FCDE);
            if not string.IsNullOrEmpty(FCDE) then
            begin
                CDE_ReplaceFuncData();
            end;

            Repeat
                FEFG := '';
                FEFG := EFG_GetEFG();
                Log.i('EFG: ' + FEFG);
                if not string.IsNullOrEmpty(FCDE) and not string.IsNullOrEmpty(FEFG) then
                begin
                    EFG_SetListFuncData();
                    EFG_ReplaceFuncData();
                end;
            Until FEFG = '';
        end;

        if FCryptType = 2 then
        begin
            CDE_SetCDE12();

            Repeat
                FGHI := '';
                FGHI := GHI_GetGHI();
                Log.i('GHI: ' + FGHI);
                if not string.IsNullOrEmpty(FCDE1) and not string.IsNullOrEmpty(FCDE2) and not string.IsNullOrEmpty(FGHI) then
                begin
                    GHI_SetListFuncData();
                    GHI_ReplaceFuncData();
                end;
            Until FGHI = '';

            if not string.IsNullOrEmpty(FCDE1) then
            begin
                CDE12_ReplaceFuncData(FCDE1);
            end;

            if not string.IsNullOrEmpty(FCDE2) then
            begin
                CDE12_ReplaceFuncData(FCDE2);
            end;

        end;


    end;
    strDeJsFile := ExtractFilePath(FJsFileName) + 'De_' + ExtractFileName(FJsFileName);
    WriteDeJsFile(strDeJsFile);

end;

On the source address GItHUB,
Source Download
Finally, I solemnly state that the decompiled JS source can not be directly loaded and run dynamically again, which involves JS syntax issues, so if the decompiled JS file is not available, do not complain..., but the analysis method given in this paper is completely feasible.

Keywords: Javascript Delphi ECMAScript

Added by Datnigz2002 on Wed, 16 Feb 2022 19:09:33 +0200