使用ChakraCore来Fuzz NScript

NScript是JScript的子集,前面的文章(http://www.nul.pw/2017/06/12/237.html)我介绍了使用NScript的方式,也提到了语法混乱,写的让人头疼的Mozilla Funfuzz的最终精简版本(http://www.nul.pw/2017/06/12/235.html),以及使用ChakraCore运行Funfuzz的壮观景象。

因为NScript事实上是一个非常精简的子集,以至于不能够支持Funfuzz那一大堆雄伟的语法,如下图:

nscript.png

事实上,先不说NScript,就连微软引以为豪的ChakraCore要支持起来都十分吃力,但是好在Funfuzz虽然代码写得奔放,但是最终生成的测试用例却格外的“人性化”。

转载请标明来源: http://nul.pw/
本文作者:blast

不过基本上看,NScript还是表现的和JScript很相似的:

代码测试
input:function p(){log(myVar)}; function q(){var myVar=2; p(); log(myVar);}; var myVar=1; log(myVar); q();
evaluation result: 1
evaluation result: 1
evaluation result: 2

为了能够取到Funfuzz的运行结果(即生成的Fuzz语句),而不修改Funfuzz的代码,(那一堆变量我实在是不敢修改啊)。我要选择更容易下手的——ChakraCore的代码。ChakraCore的print实现了类似console.log的功能,而我们可以在FunFuzz中print一下,来记录代码。

而只要我们知道print的代码,我们就可以在print时,将代码抛给NScript,这样,我们就可以同时Fuzz ChakraCore和NScript了。我知道你在想什么,wsprintf系列并不合适,因为不止print,ChakraCore的很多代码都依附类似的函数输出数据,所以我们要找到更精确的print。

print是一个很常见的名词,因此搜索并不管用,我们会搜出一大堆带print的函数。而ChakraCore也不支持阻塞的函数,比如alert之类的,这样就让我们的调试显得难以入手。不过还好,Math类下有一大堆名字独特的函数,比如反正切函数atan。Math.atan,我们搜索atan(之后,可以发现Js::Math::Atan的位置,给Atan的入口下断点。如果你不想多看一堆转换,最好是下一个参数的那个Atan。我们的代码是print(Math.atan(4))。运行后,断点停止在Atan处:

>   ChakraCore.dll!Js::Math::Atan(double x) Line 263    C++
    ChakraCore.dll!Js::Math::Atan(Js::RecyclableObject * function, Js::CallInfo callInfo, ...) Line 246 C++
    ChakraCore.dll!Js::LocalCallFunction(Js::RecyclableObject * function, void * (Js::RecyclableObject *, Js::CallInfo, ...) * entryPoint, Js::Arguments args, bool doStackProbe) Line 1313 C++
    ChakraCore.dll!Js::JavascriptFunction::CallFunction<1>(Js::RecyclableObject * function, void * (Js::RecyclableObject *, Js::CallInfo, ...) * entryPoint, Js::Arguments args) Line 1329  C++
    ChakraCore.dll!Js::InterpreterStackFrame::OP_CallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, Js::RecyclableObject * function, unsigned int flags, const Js::AuxArray<unsigned int> * spreadIndices) Line 3902 C++
    ChakraCore.dll!Js::InterpreterStackFrame::OP_ProfileCallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, Js::RecyclableObject * function, unsigned int flags, unsigned short profileId, unsigned int inlineCacheIndex, const Js::AuxArray<unsigned int> * spreadIndices) Line 3927 C++
    ChakraCore.dll!Js::InterpreterStackFrame::OP_ProfiledCallIWithICIndex<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, unsigned int flags) Line 456    C++
    ChakraCore.dll!Js::InterpreterStackFrame::ProcessProfiled() Line 86 C++
    ChakraCore.dll!Js::InterpreterStackFrame::Process() Line 3452   C++
    ChakraCore.dll!Js::InterpreterStackFrame::InterpreterHelper(Js::ScriptFunction * function, Js::ArgumentReader args, void * returnAddress, void * addressOfReturnAddress, const bool isAsmJs) Line 2039  C++
    ChakraCore.dll!Js::InterpreterStackFrame::InterpreterThunk(Js::JavascriptCallStackLayout * layout) Line 1776    C++

我们的目标当然不是Atan,而是外面的print,返回后跟踪,可以看到ChakraCore取出Next Op,并在这里:

>   ChakraCore.dll!Js::InterpreterStackFrame::OP_CallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, Js::RecyclableObject * function, unsigned int flags, const Js::AuxArray<unsigned int> * spreadIndices) Line 3888 C++
    ChakraCore.dll!Js::InterpreterStackFrame::OP_ProfileCallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, Js::RecyclableObject * function, unsigned int flags, unsigned short profileId, unsigned int inlineCacheIndex, const Js::AuxArray<unsigned int> * spreadIndices) Line 3927 C++
    ChakraCore.dll!Js::InterpreterStackFrame::OP_ProfiledCallIWithICIndex<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, unsigned int flags) Line 456    C++
    ChakraCore.dll!Js::InterpreterStackFrame::ProcessProfiled() Line 86 C++
    ChakraCore.dll!Js::InterpreterStackFrame::Process() Line 3452   C++
    ChakraCore.dll!Js::InterpreterStackFrame::InterpreterHelper(Js::ScriptFunction * function, Js::ArgumentReader args, void * returnAddress, void * addressOfReturnAddress, const bool isAsmJs) Line 2039  C++
    ChakraCore.dll!Js::InterpreterStackFrame::InterpreterThunk(Js::JavascriptCallStackLayout * layout) Line 1776    C++
    [External Code] 

可以看到调用:

JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), args);

这里的function就是最终实现print的函数。可以看到ChakraCore在这里使用了JSRT来扩展(参考我翻译的文章:http://tem.pw/?x=entry:entry170620-222216)实现了print,无论怎样,我们找到了print的位置:

-       function    0x0210c540 {signature=0x00000000 callbackState=0x00000000 nativeMethod=0x00251bc0 {ch.exe!WScriptJsrt::EchoCallback(void *, bool, void * *, unsigned short, void *)} ...}   Js::RecyclableObject *
-       [Js::JavascriptExternalFunction]    {signature=0x00000000 callbackState=0x00000000 nativeMethod=0x00251bc0 {ch.exe!WScriptJsrt::EchoCallback(void *, bool, void * *, unsigned short, void *)} ...}  Js::JavascriptExternalFunction
+       Js::RuntimeFunction {functionNameId=0x0210a720 }    Js::RuntimeFunction
        signature   0x00000000  void *
        callbackState   0x00000000  void *
        nativeMethod    0x00251bc0 {ch.exe!WScriptJsrt::EchoCallback(void *, bool, void * *, unsigned short, void *)}   void * (Js::RecyclableObject *, Js::CallInfo, void * *) *
+       wrappedMethod   0x00251bc0 {ch.exe!WScriptJsrt::EchoCallback(void *, bool, void * *, unsigned short, void *)} {signature=...}   Js::JavascriptExternalFunction *
        stdCallNativeMethod 0x00251bc0 {ch.exe!WScriptJsrt::EchoCallback(void *, bool, void * *, unsigned short, void *)}   void * (void *, bool, void * *, unsigned short, void *) *
        initMethod  0x00000000  HRESULT (void *) *
        oneBit  1   unsigned int
        typeSlots   0   unsigned int
        hasAccessors    0   unsigned int
        unused  0   unsigned int
        prototypeTypeId -1  int
        flags   0   unsigned __int64
+       FinalizableObject   {...}   FinalizableObject
-       type    0x020f2c80 {typeId=TypeIds_Function (26) flags=TypeFlagMask_None (0 '\0') javascriptLibrary=0x02110000 {...} ...}   Js::Type *
        typeId  TypeIds_Function (26)   Js::TypeId
        flags   TypeFlagMask_None (0 '\0')  TypeFlagMask
+       javascriptLibrary   0x02110000 {cacheForCopyOnAccessArraySegments=0x02122000 {cache=0x02122000 {0x00000000 <NULL>, 0x00000000 <NULL>, ...} ...} ...}    Js::JavascriptLibrary *
-       prototype   0x020f2540 {constructorCache=0x10a921b0 {ChakraCore.dll!Js::ConstructorCache Js::ConstructorCache::DefaultInstance} {...} ...}  Js::RecyclableObject *
-       [Js::JavascriptFunction]    {constructorCache=0x10a921b0 {ChakraCore.dll!Js::ConstructorCache Js::ConstructorCache::DefaultInstance} {...} ...} Js::JavascriptFunction
+       Js::DynamicObject   {auxSlots=0x00000000 {???} objectArray=0x00000000 <NULL> arrayFlags=None (0) ...}   Js::DynamicObject
+       constructorCache    0x10a921b0 {ChakraCore.dll!Js::ConstructorCache Js::ConstructorCache::DefaultInstance} {guard={value=...} ...}  Js::ConstructorCache *
+       functionInfo    0x10a93dd8 {ChakraCore.dll!Js::FunctionInfo Js::JavascriptFunction::EntryInfo::PrototypeEntryPoint} {...}   Js::FunctionInfo *
+       FinalizableObject   {...}   FinalizableObject
+       type    0x020f2520 {typeId=TypeIds_Function (26) flags=TypeFlagMask_None (0 '\0') javascriptLibrary=0x02110000 {...} ...}   Js::Type *
        entryPoint  0x0fe56270 {ChakraCore.dll!Js::JavascriptExternalFunction::StdCallExternalFunctionThunk(Js::RecyclableObject *, Js::CallInfo, ...)} void * (Js::RecyclableObject *, Js::CallInfo, ...) *
+       propertyCache   0x00000000 <NULL>   Js::TypePropertyCache *

为WScriptJsrt::EchoCallback下断点,运行过去,栈如下:

>   ch.exe!WScriptJsrt::EchoCallback(void * callee, bool isConstructCall, void * * arguments, unsigned short argumentCount, void * callbackState) Line 105  C++
    ChakraCore.dll!Js::JavascriptExternalFunction::StdCallExternalFunctionThunk(Js::RecyclableObject * function, Js::CallInfo callInfo, ...) Line 275   C++
    ChakraCore.dll!Js::LocalCallFunction(Js::RecyclableObject * function, void * (Js::RecyclableObject *, Js::CallInfo, ...) * entryPoint, Js::Arguments args, bool doStackProbe) Line 1313 C++
    ChakraCore.dll!Js::JavascriptFunction::CallFunction<1>(Js::RecyclableObject * function, void * (Js::RecyclableObject *, Js::CallInfo, ...) * entryPoint, Js::Arguments args) Line 1329  C++
    ChakraCore.dll!Js::InterpreterStackFrame::OP_CallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, Js::RecyclableObject * function, unsigned int flags, const Js::AuxArray<unsigned int> * spreadIndices) Line 3891 C++
    ChakraCore.dll!Js::InterpreterStackFrame::OP_ProfileCallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, Js::RecyclableObject * function, unsigned int flags, unsigned short profileId, unsigned int inlineCacheIndex, const Js::AuxArray<unsigned int> * spreadIndices) Line 3927 C++
    ChakraCore.dll!Js::InterpreterStackFrame::OP_ProfiledCallIWithICIndex<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > >(const Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > * playout, unsigned int flags) Line 456    C++
    ChakraCore.dll!Js::InterpreterStackFrame::ProcessProfiled() Line 86 C++
    ChakraCore.dll!Js::InterpreterStackFrame::Process() Line 3452   C++
    ChakraCore.dll!Js::InterpreterStackFrame::InterpreterHelper(Js::ScriptFunction * function, Js::ArgumentReader args, void * returnAddress, void * addressOfReturnAddress, const bool isAsmJs) Line 2039  C++
    ChakraCore.dll!Js::InterpreterStackFrame::InterpreterThunk(Js::JavascriptCallStackLayout * layout) Line 1776    C++
    [External Code] 

对AutoString str进行检视:

-       str {length=18 data=0x00486730 "1.3258176636680325" data_wide=0x00000000 <NULL> ...}    AutoString
        length  18  unsigned int
+       data    0x00486730 "1.3258176636680325" char *
+       data_wide   0x00000000 <NULL>   wchar_t *
        errorCode   JsNoError (0)   _JsErrorCode
        dontFree    false   bool

值1.3258176636680325确实就是Atan(4)的结果。

所以,我们只要修改这个函数,用它来和NScript进行通信,就可以达到我们想要的效果。

标签:none

添加新评论

captcha
请输入验证码