问题:反混淆获取调用堆栈打字稿从模糊JavaScript代码
我有记录从一个服务器上的文件,其中包含从抛出的错误,引发该日志文件的创建调用堆栈。服务器应用程序使用nodejs编写在typescript中,但是将gest转换为javascript,并且javascript代码使用google闭包编译器进行混淆处理。现在我的调用堆很难解释,我试图通过去混淆js代码来改变,使用闭包编译器创建的源映射,然后再次使用源映射,将js调用堆“untranspile”到打字稿调用堆。
我的局限性
我访问源的地图,源代码(TS和js)和混淆代码,但我不能更改代码本身,因此即时通讯坚持与当前调用堆栈。我也可以访问所有选项以及混淆代码的代码/工具,因此我可能会将某些需要的信息存储在文件中(信息未显示在源映射中),就像其他映射一样。
思路和尝试
第一次尝试是简单地interprete源的地图和与该信息反混淆调用堆栈(deobfuscating是最困难的部分),但试图了解CC创建源的方式后,我地图我有一些问题: cc不只是将一个名称映射到另一个名称,因为他多次重复使用某些名称(如a,f或这些“名称”)。因此,可能会有一些函数带有一些匿名函数或嵌套函数,其中名称f被多次使用,但由于范围而在每个上下文中具有不同的含义。
下一个想法是简单地相信调用堆栈。明白我的意思是,你必须了解(如果我了解,正确的),并抄送如何创建和管理映射:
return method.call(thisObj, args[0], args[1]);
这条线被混淆到这一点(我离开了空格了解索引更好) :
return f.call(d, a[0], a[1]);
现在有此一行创建了多个映射,单一映射这样看:
export interface MappingItem {
source: string;
generatedLine: number;
generatedColumn: number;
originalLine: number;
originalColumn: number;
name: string | null;
}
在此MAPP唯一重要信息ing实例是列和名称。一些映射包含其他名称不是。那些不包含名字的名字被用来为那些有名字的人建立一些范围,以便找出名字/替换名字开始和结束的地方(索引)。
使用上述两种说法这个逻辑的一个例子:
Generated │ Original │ Name │ Scope
0 │ 16 │ null │ ━━━┓
15 │ 23 │ method │ x │
16 │ 23 │ call │ x │
21 │ 23 │ null │ ━┓ │
22 │ 35 │ thisObject │ x│ │
23 │ 23 │ null │ ━┛ │
25 │ 44 │ args │ x │
26 │ 44 │ null │ ━┓ │
27 │ 49 │ null │ ?│ │
28 │ 44 │ null │ ━┛ │
29 │ 23 │ null │ ━━┓│
31 │ 53 │ args │ x ││
32 │ 53 │ null │ ━┓││
33 │ 58 │ null │ ?│││
34 │ 53 │ null │ ━┛││
35 │ 23 │ null │ ━━┛│
36 │ 16 │ null │ ━━━┛
使用该调用堆栈,我想解决一切从applications.js。所有的传输和混淆的JS代码都在那里。休息是无关紧要的:
at do2 (c:\Users\me\test\js\test.js:14:11)
at do1 (c:\Users\me\test\js\test.js:11:5)
at Server.<anonymous> (c:\Users\me\test\js\test.js:6:5)
at f (c:\Users\me\build\transpiled\obfuscated\application.js:235:18)
at Object.a.safeInvoke (c:\Users\me\build\transpiled\obfuscated\application.js:285:27)
at Server.g.getWrappedListener (c:\Users\me\build\transpiled\obfuscated\application.js:3313:17)
at emitTwo (events.js:106:13)
at Server.emit (events.js:191:7)
at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:546:12)
at HTTPParser.parserOnHeadersComplete (_http_common.js:99:23)
现在使用来自sourcemap的信息很容易得到原始的行和列,但名称不是。我试着先尝试没有来自代码的信息,准备好前一个位置(行和列)以引用下一行的名称。因此,如果我想解析f,我会查找它被调用的地方(285:18),然后在源地图中查找它,我会在其中找到它的名称。但是对于这个过程我总是需要知道它在哪里被调用的地方总是。现在这就是问题所在。因为如果函数会被存储在一个变量中,或者是匿名的或者其他类似的东西,那么我有一个问题。
f.call(d, a[0], a[1]);
而且我才注意到,某些方法,如在这方面呼吁,不要在调用堆栈,这是另一个问题上市。所以,现在我可以至少解决名称,如果我可以确定我是否知道他们在哪里被调用,以及他们是否在调用堆栈中。但我不是这样的一半的解决方案。
我的第二次尝试使用JavaScript的前途模块,我发现:stacktrace-js
该模块是为浏览器发出但JS和具有不良的打字稿文档/分型,但它显然是写在打字稿。这也会导致在本地读取文件时不支持,因为它们总是被xmlhttprequests调用。这个部分有一些解决方法,但是模块非常复杂(可能是由于被编译的代码),还有其他部分也不支持我,使用本地文件。它只是太重写/改变它与nodejs正常工作....
你知道一个更干净的方式与模块做?我还想过使用源代码解析器来获取更多的上下文以支持源地图(在那些恶意的.call方法的情况下)。也许我可以写我自己的源代码解析器,如果有一个文档的所有例外,我不得不注意当解析代码和解释它... 也许有另一种方式,我目前正在监督...
错误如此难以重现,您无法加载未混淆的版本,在那里生成并调试错误?这将是一个简单的方法,至少这一次。 – ASDFGerte
现在你的问题看起来像寻找建议,这是脱离主题。让我们来更具体一点。你能用'.ts'文件中的几行代码重现问题吗?你使用哪个tsc标志?你使用哪个cc标志?输出文件是什么样的?最后,你没有得到什么预期的行为。 – styfle