Javascript 终级“解密”

解密加上引号,因为并不是真正的解密。

现在很多网站不让你看js源码,就想办法变形,最后再document.write出来。

显然不管它怎么变形,最后总要调用document.write,我们直接在document.write的实现处,

用native调试来下个断点,不就可以读出来了?

找到document.write函数:

C:\>syminfo /S E:\symbol C:\WINDOWS\ie7\mshtml.dll | grep ::write 7DDA72FB[+   0] ?writeln@CDocument@@QAGJPAUtagSAFEARRAY@@@Z             public:long __stdcall CDocument::writeln(struct tagSAFEARRAY *) 7DCE0741[+   0] ?write@CDocument@@QAGJPAUtagSAFEARRAY@@@Z               public:long __stdcall CDocument::write(struct tagSAFEARRAY *)

显然,直接在这两个函数下断点就可以了。

下完需要读一个VARIANT结构,里面是一个VT_I8的safearray,需要了解safearray的结构,就不赘述了。

 因为还有更好的办法!
用firebug直接看就是了。原来也不清楚,原来firebug看时,一个javascript段里调用了document.write之后,就会在dom树里紧跟着看到另一个<script></script>的段。所以,直接用firebug翻看就行了。真是简单啊。

翻看后可以找个工具把代码格式化一下。

有个软件叫sourceformatx,好像已经有四年没有更新了。找了一下crack的文章,说这个软件破解不好会直接破坏系统,因此没有人破解。由于四年过了,现在已经可以搜到完美破解版,但是不是真的完美呢?要是有一点不完美,系统就要挂了,怕怕。所以先不用了,要用也在vmware里用。

thank creese@newsmth.

 

晕,我的韩国代理不能用了。

222.122.249.5:8080

非常快非常好的代理,如今挂了。不能连了。

google了一把这个IP,一堆的记录啊天啦。

不过现在终于倒了。

也好,搜这个IP能找到很多不错的代理网站。

用代理这个关键字反而找不到这么好的。呵呵,让SEO见鬼去吧。

windows 注册表的初始化

看了看wrk的代码,发现一个函数会调用ZwCreateFile打开注册表的文件,这个函数就是CmpOpenHiveFiles

这个函数会打开两个注册表文件,master为不带后辍的,secondary为带后辍的。

system32\config\system和software就是这样被加载的。

 

查找过程,先找SAM,这个词不常见,grep一下找到一个配置表:

HIVE_LIST_ENTRY CmpMachineHiveList[] = {     { L"HARDWARE", L"MACHINE\\", NULL, HIVE_VOLATILE    , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},     { L"SECURITY", L"MACHINE\\", NULL, 0                , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},     { L"SOFTWARE", L"MACHINE\\", NULL, 0                , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},     { L"SYSTEM",   L"MACHINE\\", NULL, 0                , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},     { L"DEFAULT",  L"USER\\.DEFAULT", NULL, 0           , CM_CMHIVE_FLAG_UNTRUSTED  ,   NULL,   FALSE,  FALSE,  FALSE},     { L"SAM",      L"MACHINE\\", NULL, HIVE_NOLAZYFLUSH , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},     { NULL,        NULL,         0, 0                   , 0                         ,   NULL,   FALSE,  FALSE,  FALSE}     };

注册表应该就是从这里初始化的了。

再找引用:

    for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) {         ASSERT( CmpMachineHiveList[i].Name != NULL );         //           // just spawn the Threads to load the hives in parallel         //           Status = PsCreateSystemThread(             &Thread,             THREAD_ALL_ACCESS,             NULL,             0,               NULL,             CmpLoadHiveThread,             (PVOID)(ULONG_PTR)(ULONG)i             );           if (NT_SUCCESS(Status)) {             ZwClose(Thread);         } else {             //               // cannot spawn thread; Fatal error             //               CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_HIVE_LIST,3,i,Status);         }        }   

这里为每个hive创建一个线程,进入CmpLoadHiveThread函数:

  

  // <sysroot>\config\hive     if (CmpMachineHiveList[i].CmHive == NULL) {         //         // Hive has not been initialized in any way.         //         CmpMachineHiveList[i].Allocate = TRUE;         Status = CmpInitHiveFromFile(&FileName,                                      CmpMachineHiveList[i].HHiveFlags,                                      &CmHive,                                      &(CmpMachineHiveList[i].Allocate),                                      CM_CHECK_REGISTRY_CHECK_CLEAN                                      );         if ( (!NT_SUCCESS(Status)) ||              (!CmpShareSystemHives && (CmHive->FileHandles[HFILE_TYPE_LOG] == NULL)) )         {             ErrorParameters = &FileName;             ExRaiseHardError(                 STATUS_CANNOT_LOAD_REGISTRY_FILE,                 1,                 1,                 (PULONG_PTR)&ErrorParameters,                 OptionOk,                 &ErrorResponse                 );         }  

CmpInitHiveFromFile会调用CmpOpenHiveFiles,后者会调用zwcreatefile打开相应的注册表文件。

如果要保护注册表,在创建线程前处理一下就好了。还只是猜想,哪天闲出毛病了再试试。

 

绕过dbghelp手动获取unloaded module(dll)信息

dbghelp有个功能,那就是MiniDumpWithUnloadedModules,
当os维护了已经unload的dll的列表时,它会在minidump文件中存入unloaded modules的信息。
只可惜的是,msdn中明说了,dbghelp 5.1并不支持这个标志。
看了一下winxpsp2自带的dbghelp.dll,恰好是这个版本的。

这一个标志是很重要的,因为某些BUG,经查恰好运行到一个非法的地址时Crash,
而这个非法的地址怎么看都像是原来有一个dll恰好加载在这里,但如今
这个dll已经被FreeLibrary了。如果有了这个unload modules的信息,
那么这个BUG就很容易找出来。如果没有的话,就麻烦了,因为程序代码
中都是com指针,虚表调来调处的根本不知道调用处正常情况应当调用的是哪个dll。
既然这个标志重要,自然应当把它启用,但winxp sp2恰恰不支持,如果为了这一个功能
就打包一个体积不小的dbghelp.dll的话,也划不来。

因此,想到一点:
何不自己把unloaded modules的信息,记载下来跟.dmp文件一起上报呢?

如是开始研究,先写了一个很小的程序来实现产生minidump的功能,然后用ollydbg来调试,
看dbghelp.dll是如何拿到unloaded modules的信息的。
程序虽小,五脏俱全,代码如下:

int Filter(_EXCEPTION_POINTERS * source, _EXCEPTION_POINTERS * dest) {  *dest->ContextRecord = *source->ContextRecord;  *dest->ExceptionRecord = *source->ExceptionRecord;  return EXCEPTION_EXECUTE_HANDLER; } void Doxx(EXCEPTION_POINTERS * p) {  HANDLE ho = CreateFile(L"oo.dmp", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, 0, 0);  _MINIDUMP_EXCEPTION_INFORMATION ExInfo;  ExInfo.ThreadId          = GetCurrentThreadId();  ExInfo.ExceptionPointers = p;  ExInfo.ClientPointers    = TRUE;  MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), ho, MiniDumpWithUnloadedModules, &ExInfo, 0, 0); } int main() {  EXCEPTION_RECORD ExceptionRecord;  CONTEXT ContextRecord;  EXCEPTION_POINTERS ptr;  ptr.ExceptionRecord = &ExceptionRecord;  ptr.ContextRecord = &ContextRecord;  __try  {   *(int*)0 = 0;  }  __except (Filter(GetExceptionInformation(), &ptr))  {   Doxx(&ptr);  } }

然后反复查找应用的断点,找字符串找到:
GenGetProcessInfo.EnumUnloadedModules(0x%x) failed, 0x%08x
就从它入手了,找到相应的代码引用,然后看上下文,不多久找到了
NtWin32LiveSystemProvider::EnumUnloadedModules 函数,
一看实现,是从已经有的内存里copy一个字符串出来而已。
那还要找到这段内存如何来的,在指定改写处下硬点断点重跑,
发现这个内存是用ReadProcessMemory读来的,读的地址是7C99D8C0,
跑到那里一看,果然有unloaded 的 shimengine.dll的信息。
看了下od的log确认这个dll在exe的入口点之前被卸载。

接下来就查这个7C99D8C0是哪里来的了,往上翻代码,发现是调了一个函数,
在那里下断点重跑,找到了:

030656DE  |. FFD0    CALL EAX   ;  ntdll.RtlGetUnloadEventTrace

google一把RtlGetUnloadEventTrace,发现msdn2上居然有详细说明。
到是出乎意料。

OK,大功告成,总结如下:

windows xp sp2和2003 sp1以后,ntdll维护了unloaded module的信息。
由ntdll写入一个叫RtlpUnloadEventTrace的数组,并导出函数
RtlGetUnloadEventTrace返回该数组。代码实现:

#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64 typedef struct _RTL_UNLOAD_EVENT_TRACE {     PVOID BaseAddress;   // Base address of dll     SIZE_T SizeOfImage;  // Size of image     ULONG Sequence;      // Sequence number for this event     ULONG TimeDateStamp; // Time and date of image     ULONG CheckSum;      // Image checksum     WCHAR ImageName[32]; // Image name } RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE; RTL_UNLOAD_EVENT_TRACE RtlpUnloadEventTrace[RTL_UNLOAD_EVENT_TRACE_NUMBER]; PRTL_UNLOAD_EVENT_TRACE RtlGetUnloadEventTrace() {     return RtlpUnloadEventTrace; }

我们只需要调用RtlGetUnloadEventTrace即可拿到指向数组首元素的指针。
但是这个数组有多少项呢?msdn2上说是有64项,但dbghelp只读了16个,为什么呢?
如果64个,占用内存大小应当是:
sizeof(RTL_UNLOAD_EVENT_TRACE) * 64 = 54h*40h = 1500h
打开ntdll.dll的data segment一看,其实大小并没有这么多,只有540h个字节,
也就是说,至少在windows xp sp2,这个结构的大小只有10h即16个元素。
也许在其它版本如vista更大了吧,不管它。

到这里,要做的,无非就是GetProcAddress拿到RtlGetUnloadEventTrace,
拿到返回的指针,再读出16个结构出来,然后整理成我需要的报告形式,与
.dmp一起上报就好了。