以子之矛,陷子之盾,何如?——使用ChakraCore来Fuzz NScript (2)
我在很早以前做了一个多进程的Fuzz程序,其实最终的实现很简单,就是类似一个使用socket互相通信的程序,好似QQ互相发送消息一样。Server和Client约定好一组消息,互相通信。
代码实现很简单,百度随便一搜就是一大堆,比如:http://blog.csdn.net/yaopeng_2005/article/details/6696105,可以直接拿来用。NScript处,因为我需要将待分析的代码传给rs
函数,在我没有传递完成前,整个流程都可以停滞。因此NScript作为客户端,只需要一直等待Server传来的Fuzz代码,并从Buffer中取出代码,传递给rs
即可。
callClient.cpp
// callClient.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <Winsock2.h>
#pragma comment(lib, "ws2_32.lib")
void main()
{
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
return;
}
if (LOBYTE(wsaData.wVersion ) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return;
}
for (int index = 0; ; index++)
{
SOCKET sockClient = socket(AF_INET,SOCK_DGRAM, 0);
int len = sizeof(SOCKADDR);
SOCKADDR_IN local;
local.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
local.sin_family = AF_INET;
local.sin_port = htons(27015);
DWORD dwSize = MAX_PATH;
char sendBuf[MAX_PATH] = { 0 };
sprintf(sendBuf, "%3d,", index);
//client(ChakraCore) shall send a file name to client. incase of buffer has a limit of 64kb.
strcat(sendBuf, "c:\\test\\wow.js");
sendto(sockClient, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&local, len);
/*char recvBuf[50];
recvfrom(sockClient,recvBuf,50,0,(SOCKADDR*)&local,&len);
printf("my reply is : %s\n",recvBuf);
printf("%s\n",inet_ntoa(local.sin_addr));
*/
closesocket(sockClient);
Sleep(2000);
WSACleanup();
}
}
callServer.cpp
// callServer.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <Winsock2.h>
#pragma comment(lib, "ws2_32.lib")
void main()
{
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
return;
}
if ( LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
WSACleanup();
return;
}
SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM, 0);
int len = sizeof(SOCKADDR);
SOCKADDR_IN from;
SOCKADDR_IN local;
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(27015);
int bindResult = bind(sockSrv, (SOCKADDR*)&local, len);
while(1)
{
DWORD dwSize = MAX_PATH;
char recvBuf[MAX_PATH];
//server(NScript) will receive a buffer contains filename of generated fuzzer.
recvfrom(sockSrv, recvBuf, dwSize, 0, (SOCKADDR*)&from, &len);
printf("%s\n", recvBuf);
printf("%s\n", inet_ntoa(local.sin_addr));
/*char sendBuf[50];
sprintf(sendBuf, "Welcome %s to here!", inet_ntoa(from.sin_addr));
sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&from, len);
*/
Sleep(2000);
}
closesocket(sockSrv);
WSACleanup();
}
而Client端如果发生异常,处理起来就更容易了,使用SetUnhandledExceptionFilter可以设置TopLevelExceptionFilter。这是一个定义为
LONG WINAPI UnhandledExceptionFilter(__in struct _EXCEPTION_POINTERS* pExceptionInfo)
的函数,可以在pExceptionInfo中取到异常信息并记录。
所以,这里的实现比较容易,
1、在NScript侧,WinMain进入时,调用
SetUnhandledExceptionFilter()
int WinMain(...)
{
...
LPTOP_LEVEL_EXCEPTION_FILTER originalFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
...
}
2、MyUnhandledExceptionFilter里面可以收集异常信息并告警
LONG WINAPI MyUnhandledExceptionFilter(__in struct _EXCEPTION_POINTERS* pExcepInfo)
{
DWORD dwCrashPid = GetCurrentProcessId();
DWORD dwCrashTid = GetCurrentThreadId();
pExcepInfo->ExceptionRecord.ExceptionCode;
pExcepInfo->ExceptionRecord.ExceptionAddress;
alert!
...
}
3、NScript部分,循环等待,并在接受到数据时调用__rs
4、ChakraCore部分
JsValueRef __stdcall WScriptJsrt::EchoCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
{
for (unsigned int i = 1; i < argumentCount; i++)
{
……
if (i > 1)
{
wprintf(_u(" "));
}
////////////////////////////////////////////////////////
SEND CODE HERE
////////////////////////////////////////////////////////
wprintf(_u("%ls"), str.GetWideString());
}
}
……
}
……