synchrony icon indicating copy to clipboard operation
synchrony copied to clipboard

Failed to find string array with identifier for push/shift calc

Open hazarkarabay opened this issue 4 years ago • 3 comments

I'm trying to deobfuscate a script that I believe produced by a recent version of javascript-obfuscator. (based on original file date) synchrony master gives this message for it: Error: Failed to find string array with identifier "_0x26be" for push/shift calc

synchrony master full output
$ synchrony deobfuscate -l obf_source.js 
Running Simplify transformer
Running MemberExpressionCleaner transformer
Running LiteralMap transformer
Running DeadCode transformer
Running Demangle transformer
Running StringDecoder transformer
Caught an error while attempting to run AST visitor!

node = Node {
  type: 'ExpressionStatement',
  start: 12017,
  end: 12936,
  range: [ 12017, 12936 ],
  expression: Node {
    type: 'CallExpression',
    start: 12018,
    end: 12934,
    range: [ 12018, 12934 ],
    callee: Node {
      type: 'FunctionExpression',
      start: 12018,
      end: 12896,
      range: [Array],
      id: null,
      params: [Array],
      generator: false,
      expression: false,
      async: false,
      body: [Node]
    },
    arguments: [ [Node], [Node] ],
    optional: false
  }
} 
err = Error: Failed to find string array with identifier "_0x26be" for push/shift calc
    at r (/somepath/synchrony-git/dist/index.js:28:23401)
    at ExpressionStatement (/somepath/synchrony-git/dist/index.js:28:23825)
    at s (/somepath/synchrony-git/dist/index.js:25:147)
    at Object.skipThrough (/somepath/synchrony-git/node_modules/acorn-walk/dist/walk.js:186:39)
    at s (/somepath/synchrony-git/dist/index.js:25:133)
    at Object.base.Program.base.BlockStatement.base.StaticBlock (/somepath/synchrony-git/node_modules/acorn-walk/dist/walk.js:198:7)
    at s (/somepath/synchrony-git/dist/index.js:25:133)
    at m (/somepath/synchrony-git/dist/index.js:28:22)
    at ge.shiftFinder (/somepath/synchrony-git/dist/index.js:28:23584)
    at ge.<anonymous> (/somepath/synchrony-git/dist/index.js:28:28343)
shifted = 0 arrays = 0
Running Simplify transformer
Running MemberExpressionCleaner transformer
Running Desequence transformer
Running ControlFlow transformer
_0x3be7d3.QBOVx = FunctionExpression
_0x55be3e.Muqjv = FunctionExpression
_0x55be3e.MANuw = FunctionExpression
_0x1e92a6.umaHT = FunctionExpression
_0x15da49.xaqBn = MemberExpression
_0x174d29.RybNP = FunctionExpression
_0x26bc7f.lpvyc = FunctionExpression
_0x1baf72.get = FunctionExpression
_0x39c52a.slsEJ = FunctionExpression
_0x2938cd.zQwQi = MemberExpression
_0x5ebf21.eqnhH = MemberExpression
_0x5ebf21.IrlFW = FunctionExpression
_0x5ebf21.HiOsj = MemberExpression
_0x5ebf21.KUNfU = MemberExpression
_0x5ebf21.MnYfH = Literal
_0x5ebf21.nHfBB = FunctionExpression
_0x524a7b.VvKOI = CallExpression
_0x524a7b.UMqSH = FunctionExpression
_0x524a7b.EQQdD = FunctionExpression
_0x524a7b.pawBQ = FunctionExpression
_0x524a7b.IgJbK = FunctionExpression
_0x524a7b.MNZgl = BinaryExpression
_0x524a7b.NYvdU = CallExpression
_0x524a7b.ZKnsI = BinaryExpression
_0x524a7b.oHHMx = FunctionExpression
_0x524a7b.PxbNj = CallExpression
_0x524a7b.dfIMK = FunctionExpression
_0x524a7b.DqcNk = BinaryExpression
_0x524a7b.njPFE = FunctionExpression
_0x524a7b.HQKnJ = FunctionExpression
_0x524a7b.oqkTr = CallExpression
_0x524a7b.ljLXN = FunctionExpression
_0x524a7b.Umlws = Literal
_0x524a7b.uwVxN = Literal
_0x524a7b.OsVpw = FunctionExpression
_0x524a7b.mofjA = CallExpression
_0x524a7b.FJZEj = FunctionExpression
_0x524a7b.NyEjJ = CallExpression
_0x524a7b.imafF = FunctionExpression
_0x524a7b.sdzMS = CallExpression
_0x524a7b.ECcXn = FunctionExpression
_0x524a7b.ysXTX = Literal
_0x524a7b.cWsSV = BinaryExpression
_0x524a7b.AKpNp = FunctionExpression
_0x524a7b.YImoG = FunctionExpression
_0x524a7b.LgbhA = Literal
_0x524a7b.TrEIz = CallExpression
_0x524a7b.KZGCi = CallExpression
_0x524a7b.ufMdb = FunctionExpression
_0x524a7b.scQtS = FunctionExpression
Found control flow node id = _0x3be7d3 #fn = 1 #lit = 0
Found control flow node id = _0x55be3e #fn = 0 #lit = 0
Found control flow node id = _0x1e92a6 #fn = 0 #lit = 0
Found control flow node id = _0x174d29 #fn = 0 #lit = 0
Found control flow node id = _0x26bc7f #fn = 1 #lit = 0
Found control flow node id = _0x39c52a #fn = 0 #lit = 0
Running Desequence transformer
Running MemberExpressionCleaner transformer
Running Simplify transformer
Running DeadCode transformer
Running Simplify transformer
Running DeadCode transformer

Maybe I'm misinterpreting the error message but there is a _0x26be string array on the very top of the source. Any pointers are appreciated and sorry for not able to provide a smaller source file.

Source (obfuscated): https://gist.github.com/hazarkarabay/ad4a58939f234be78f369880fbcfbc9a Result: https://gist.github.com/hazarkarabay/e2f542a6cc2ec228aafa70e81c996caa

The 2.3.0 release gives different set of error messages; Push/shift calculation failed (iter=1>maxLoops=0) and TypeError: UnaryExpression argument is not Literal

synchrony 2.3.0 full output
$ synchrony deobfuscate obf_source.js 
Running Simplify transformer
Running MemberExpressionCleaner transformer
Running LiteralMap transformer
Running DeadCode transformer
Running Demangle transformer
Running StringDecoder transformer
Caught an error while attempting to run AST visitor!

node = Node {
  type: 'ExpressionStatement',
  start: 12017,
  end: 12936,
  range: [ 12017, 12936 ],
  expression: Node {
    type: 'CallExpression',
    start: 12018,
    end: 12934,
    range: [ 12018, 12934 ],
    callee: Node {
      type: 'FunctionExpression',
      start: 12018,
      end: 12896,
      range: [Array],
      id: null,
      expression: false,
      generator: false,
      async: false,
      params: [Array],
      body: [Node]
    },
    arguments: [ [Node], [Node] ],
    optional: false
  }
} 
err = Error: Push/shift calculation failed (iter=1>maxLoops=0)
    at n (/somepath/synchrony-git/dist/index.js:28:19527)
    at ExpressionStatement (/somepath/synchrony-git/dist/index.js:28:20577)
    at s (/somepath/synchrony-git/dist/index.js:25:147)
    at Object.skipThrough (/somepath/synchrony-git/node_modules/acorn-walk/dist/walk.js:186:39)
    at s (/somepath/synchrony-git/dist/index.js:25:133)
    at Object.base.Program.base.BlockStatement.base.StaticBlock (/somepath/synchrony-git/node_modules/acorn-walk/dist/walk.js:198:7)
    at s (/somepath/synchrony-git/dist/index.js:25:133)
    at d (/somepath/synchrony-git/dist/index.js:28:22)
    at ie.shiftFinder (/somepath/synchrony-git/dist/index.js:28:20336)
    at ie.<anonymous> (/somepath/synchrony-git/dist/index.js:28:23355)
Caught an error while attempting to run AST visitor!

node = Node {
  type: 'CallExpression',
  start: 11429,
  end: 11448,
  range: [ 11429, 11448 ],
  callee: Node {
    type: 'Identifier',
    start: 11429,
    end: 11436,
    range: [ 11429, 11436 ],
    name: 'Boolean'
  },
  arguments: [
    Node {
      type: 'UnaryExpression',
      start: 11437,
      end: 11447,
      range: [Array],
      operator: '~',
      prefix: true,
      argument: [Node]
    }
  ],
  optional: false
} 
err = TypeError: UnaryExpression argument is not Literal
    at J (/somepath/synchrony-git/dist/index.js:28:9515)
    at X (/somepath/synchrony-git/dist/index.js:28:9862)
    at /somepath/synchrony-git/dist/index.js:28:13772
    at Array.map (<anonymous>)
    at literals_to_arg_array (/somepath/synchrony-git/dist/index.js:28:13760)
    at CallExpression (/somepath/synchrony-git/dist/index.js:28:22961)
    at s (/somepath/synchrony-git/dist/index.js:25:147)
    at Object.skipThrough (/somepath/synchrony-git/node_modules/acorn-walk/dist/walk.js:186:39)
    at s (/somepath/synchrony-git/dist/index.js:25:133)
    at Object.base.UnaryExpression.base.UpdateExpression (/somepath/synchrony-git/node_modules/acorn-walk/dist/walk.js:373:5)
Running Simplify transformer
Running MemberExpressionCleaner transformer
Running Desequence transformer
Running ControlFlow transformer
_0x3be7d3.QBOVx = FunctionExpression
_0x55be3e.Muqjv = FunctionExpression
_0x55be3e.MANuw = FunctionExpression
_0x1e92a6.umaHT = FunctionExpression
_0x15da49.xaqBn = MemberExpression
_0x174d29.RybNP = FunctionExpression
_0x26bc7f.lpvyc = FunctionExpression
_0x1baf72.get = FunctionExpression
_0x39c52a.slsEJ = FunctionExpression
_0x2938cd.zQwQi = MemberExpression
_0x5ebf21.eqnhH = MemberExpression
_0x5ebf21.IrlFW = FunctionExpression
_0x5ebf21.HiOsj = MemberExpression
_0x5ebf21.KUNfU = MemberExpression
_0x5ebf21.MnYfH = Literal
_0x5ebf21.nHfBB = FunctionExpression
_0x524a7b.VvKOI = CallExpression
_0x524a7b.UMqSH = FunctionExpression
_0x524a7b.EQQdD = FunctionExpression
_0x524a7b.pawBQ = FunctionExpression
_0x524a7b.IgJbK = FunctionExpression
_0x524a7b.MNZgl = BinaryExpression
_0x524a7b.NYvdU = CallExpression
_0x524a7b.ZKnsI = BinaryExpression
_0x524a7b.oHHMx = FunctionExpression
_0x524a7b.PxbNj = CallExpression
_0x524a7b.dfIMK = FunctionExpression
_0x524a7b.DqcNk = BinaryExpression
_0x524a7b.njPFE = FunctionExpression
_0x524a7b.HQKnJ = FunctionExpression
_0x524a7b.oqkTr = CallExpression
_0x524a7b.ljLXN = FunctionExpression
_0x524a7b.Umlws = Literal
_0x524a7b.uwVxN = Literal
_0x524a7b.OsVpw = FunctionExpression
_0x524a7b.mofjA = CallExpression
_0x524a7b.FJZEj = FunctionExpression
_0x524a7b.NyEjJ = CallExpression
_0x524a7b.imafF = FunctionExpression
_0x524a7b.sdzMS = CallExpression
_0x524a7b.ECcXn = FunctionExpression
_0x524a7b.ysXTX = Literal
_0x524a7b.cWsSV = BinaryExpression
_0x524a7b.AKpNp = FunctionExpression
_0x524a7b.YImoG = FunctionExpression
_0x524a7b.LgbhA = Literal
_0x524a7b.TrEIz = CallExpression
_0x524a7b.KZGCi = CallExpression
_0x524a7b.ufMdb = FunctionExpression
_0x524a7b.scQtS = FunctionExpression
Found control flow node id = _0x3be7d3 #fn = 1 #lit = 0
Found control flow node id = _0x55be3e #fn = 0 #lit = 0
Found control flow node id = _0x1e92a6 #fn = 0 #lit = 0
Found control flow node id = _0x174d29 #fn = 0 #lit = 0
Found control flow node id = _0x26bc7f #fn = 1 #lit = 0
Found control flow node id = _0x39c52a #fn = 0 #lit = 0
Running Desequence transformer
Running MemberExpressionCleaner transformer
Running Simplify transformer
Running DeadCode transformer
Running Simplify transformer
Running DeadCode transformer

hazarkarabay avatar Apr 14 '22 20:04 hazarkarabay

Encountered my own of these in the wild and decided to give it a go, with the addition of a small hack (aside from actual working code) I'm able to get it to deobfuscate my specific case.

I'm however not too sure of where I should manage things it identifies as missing decoders, such as:

var _0x15cb61 = function (_0x231a76, _0x41587e) {
  var _0x3ff030 = _0x5e893b
  return (
    Math[_0x3ff030(0x2ba)](Math['random']() * (_0x41587e + 0x1 - _0x231a76)) +
    _0x231a76
  )
}

Where _0x5e893b is a reassignment of the handled global decode func:

var _0x4283 = function (_0x1cc98f, _0x55ec98) {
  _0x1cc98f = _0x1cc98f - 0x1de
  var _0x5c48c0 = _0x5c48[_0x1cc98f] // <- Array of strings at the start of the file
  return _0x5c48c0
}

Or in the case of the gist from this issue:

var _0x499549 = function (_0x5268af, _0x3322eb, _0x5ca66e, _0x51471c) {
      return _0x5904(_0x51471c - -0x2c0, _0x3322eb)
}

Where _0x5904 is a string array (RC4) decode func.

4JX avatar May 30 '22 15:05 4JX

Hi - I am hoping soon I will have time to rewrite the string decoder so that it is less poorly written and requires less work to write in support for edge cases and older versions of js-obfuscator.

It appears that the problem here is that it is not finding the decoder functions so it won't find the string arrays to locate in the function. It is "easy" to fix manually if you compare the functions from an obfuscated file to the one that is failing for you and then placing breakpoints on the if statements in the walkSimple calls inside stringdecoder.ts for the node finders to see which ones are failing and fixing in the obfuscated script manually.

Hopefully if time permits I'd like to write a library to read functions asts and compare them to schemas and pull out variables from them so it's a lot easier to debug why certain nodes aren't found (like the decoder functions, string array cache functions and the array rotate push/shift func).

Please do let me know if I am misunderstanding the issue here and I will see if I can implement any quick fixes before I am able to finish rewriting the string decoder

relative avatar May 31 '22 04:05 relative

Please do let me know if I am misunderstanding the issue here and I will see if I can implement any quick fixes before I am able to finish rewriting the string decoder

Its more confusion from my part on where the deobfucator's code is supposed to handle these cases than anything else.

Ie. It detects them as decoders, but they are not really decoders per se (as in one is a proxy function to the actual decoder one and the other is a bit of code that uses a decoder func but is not one itself). So I don't really know if I should be looking at fixing this in the stringdecoder.ts step, the simplify.ts/demangle.ts one, etc etc.

On a completely and 100% unrelated note, I saw you forked the js confuser repo, are you planning to give that a go too? Might want to chime in for the learning experience.

4JX avatar May 31 '22 10:05 4JX