SCA二级制检测能力扩展
背景简介
Synopsys Detect 旨在本地集成到构建/CI 环境中,并支持用于静态分析的所有 Coverity 语言。
对于 Black Duck 和 Black Duck 二进制分析,它可以更轻松地使用各种语言和包管理器设置和扫描代码库,以识别开源风险。
谢老师需要了解客户端进行扫描的整个动作之后如何和云端沟通以及和Hub沟通的一些细节
客户端
先说结果再说过程
结果是二进制桌面客户端逆向分析是可行的, 没有混淆加壳操作, 没有R0内核保护, 如果对客户端进行逆向分析,
但是我在分析他们的Github开源上Java写的客户端也很完美, 虽然我还没有跑过Java客户端的流程
如果完整去分析细节,可能得先了解Java端的分析软件所做的事情, 再去着重以这个逻辑看二进制桌面软件流程
了解原先Java源码所做的事情可能需要一周、再去逆向二进制桌面软件交互流程又得需要一周多
并且不排除数据是否有涉加密的情景
二进制桌面客户端过程
客户端全部静态包在一个执行文件, 导致一个客户端二进制exe特别大, 达200mb
函数数量达百万级别, 这导致的另一个问题就是IDA pro、OD这类的软件运行特别卡顿
其次这个客户端没有进行VMP之类的加壳软件进行混淆和代码膨胀(我看执行流是正常的)
还有这个客户端纯R3, 没有进行客户端代码防护, 比如R0进程的句柄保护、ObRegisterCallback回调监控等操作(不让其他动态调试器调试进程、或者跨进程读写内存)
静态分析
整个客户端使用系统库情况
- ffmpeg
- 利用了ffame、buffer、dict、packet等数据结构存数据、并且大量的codec编解码
- WS2_32
- KERNEL32
- 利用大量的Thread线程、Event事件同步、File文件操作、LoadLibrary&ProcAddress函数call
- WINHTTP
- AVDAPI
- USER32/GDI
- 其他
分析点
还有一些分析点, 基本都是网络传输或文件的交互函数
接下来是我该怎么做的大体思路
上Hook
首先直接IAT hook, 把这些系统的公共库, 部分函数Hook住, 看用户态程序的参数情况(Hook的代码进程到时候可能会进行进程挂靠共享目标进程内存, 或者进行远程注入
)
根据参数的印,以及流转变动打出来进行流程上的分析
Hook的框架就Github随意找了一下
https://github.com/tinysec/iathook
下面是案例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <windows.h>
LONG IATHook( __in_opt void* pImageBase , __in_opt char* pszImportDllName , __in char* pszRoutineName , __in void* pFakeRoutine , __out HANDLE* phHook );
LONG UnIATHook( __in HANDLE hHook );
void* GetIATHookOrign( __in HANDLE hHook );
typedef int (__stdcall *LPFN_MessageBoxA)( __in_opt HWND hWnd , __in_opt char* lpText , __in_opt char* lpCaption , __in UINT uType);
HANDLE g_hHook_MessageBoxA = NULL;
int __stdcall Fake_MessageBoxA( __in_opt HWND hWnd , __in_opt char* lpText , __in_opt char* lpCaption , __in UINT uType) { LPFN_MessageBoxA fnOrigin = (LPFN_MessageBoxA)GetIATHookOrign(g_hHook_MessageBoxA);
return fnOrigin(hWnd , "hook" , lpCaption , uType); }
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: IATHook( GetModuleHandleW(NULL) , "user32.dll" , "MessageBoxA" , Fake_MessageBoxA , &g_hHook_MessageBoxA ); MessageBoxA(NULL , "test" , "caption" , 0); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: UnIATHook( g_hHook_MessageBoxA); MessageBoxA(NULL , "test" , "caption" , 0); break; } return TRUE; }
|
远程注入我的Hook代码
上面的Hook代码可以封装成一个Dll, 到时候通过远程线程注入的方式把Dll加载到我的目标Synopsys Detect客户端进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| BOOL InjectDll(DWORD dwPid, CHAR szDllName[]) { BOOL bRet = TRUE; HANDLE hProcess = NULL, hRemoteThread = NULL; HMODULE hKernel32 = NULL; DWORD dwSize = 0; LPVOID pDllPathAddr = NULL; PVOID pLoadLibraryAddr = NULL; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); if (NULL == hProcess) { ShowError("OpenProcess"); bRet = FALSE; goto exit; } dwSize = 1 + strlen(szDllName); pDllPathAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); if (!pDllPathAddr) { ShowError("VirtualAllocEx"); bRet = FALSE; goto exit; } if (!WriteProcessMemory(hProcess, pDllPathAddr, szDllName, dwSize, NULL)) { ShowError("WriteProcessMemory"); bRet = FALSE; goto exit; } hKernel32 = LoadLibrary("kernel32.dll"); if (hKernel32 == NULL) { ShowError("LoadLibrary"); bRet = FALSE; goto exit; } pLoadLibraryAddr = GetProcAddress(hKernel32, "LoadLibraryA"); if (pLoadLibraryAddr == NULL) { ShowError("GetProcAddress "); bRet = FALSE; goto exit; } hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibraryAddr, pDllPathAddr, 0, NULL); if (hRemoteThread == NULL) { ShowError("CreateRemoteThread"); bRet = FALSE; goto exit; } exit: if (hKernel32) FreeLibrary(hKernel32); if (hProcess) CloseHandle(hProcess); if (hRemoteThread) CloseHandle(hRemoteThread); return bRet; }
|
分析关键数据
我主要看他会产出什么数据, 根据这些数据以及关键的fnOrigin, 我就开始寻找关键的代码片段, 接下来就得用上动态分析软件类似OllyDbg这类
等拿到具体的数据, OllyDbg断点停住, 我会与IDA pro联动, 寻找机函数指令所在的地址, 并进行反编译成C, 取出相关的算法逻辑和流程
我分析着发现Java写得检测也还行……真的, 我甚至觉得二进制桌面端的和Java的逻辑是一样的
Jar包客户端过程
当然也可以查看开源集成的方案,是一个Java写的Jar包
项目地址: https://github.com/blackducksoftware/synopsys-detect
项目说明: https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=introduction.html&_LANG=enus
Java检测库
执行脚本
1
| ./detect7.sh --blackduck.url=https://192.168.2.209 --blackduck.api.token=NTA2M2JlNjctMTVlYy00MmI4LTk2OTAtNzE5M2E4ODhmNWQxOjFkMTJjYjdhLWJmMWItNGQ0My05ZjJjLTRmZDlkZWUxYTg0Yg== --detect.blackduck.scan.mode=INTELLIGENT --detect.source.path=E:/some_go/src/secpoint-golang/secpoint-golang --blackduck.offline.mode=false --blackduck.trust.cert=true --detect.diagnostic.extended=true -d
|
各个部件
- InspectorExtractor 检察员
- NugetInspectorExtractor
- GradleInspectorExtractor
- PipInspectorExtractor
- ProjectInspectorExtractor
- DetectorEvaluator 检测评估器
- applicableEvaluator (应用评估器)
- extractableEvaluator (可提取评估器)
- extractionEvaluator (提取评估器)
- detectables 检测器 — 涉及太多了,简约提取
- clang
- bazel
- cargo
- dart
- git
- go
- gradle
- pip
- swift
- xcode
- yarn
- …..
检测流程
成分分析细节
当前测试项目为Golang 匹配到GIT - Git, GO_MOD - Go Mod Cli两大项
它如何操作?
GoModCliDetectable
GitDetectable
最终扫描&结果上报
runSignatureScanner 离线扫描
runSignatureScanner最终会来到这个目录进行代码进行Command执行
间接执行这个Jar包: scan.cli.jar, 这个Jar包主要做的事情scan.cli.bat\scan.cli.sh这些脚本, shell脚本又内部调用了另一个Jar包scan.cli.impl-standalone.jar
接下来就是扫描签名的一堆代码结构
服务端
1
| 06e840e31fd0 blackducksoftware/blackduck-scan:2022.2.0 "docker-entrypoint.sh" 7 days ago Up 7 days (healthy) docker-swarm_scan_1
|
优先分析这个应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| docker inspect 06e840e31fd0
... "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/4aa3a69fa2f16c000a71def7040e64b630d998938cd6d1821b60a02e899d50de-init/diff:/var/lib/docker/overlay2/b01957a681b2643e1b55f9d65992696bca3aa554ec24eef616e50df9d2cce1c8/diff:/var/lib/docker/overlay2/cf30e03bfe3429cb636acfdc9200b24026b3ac867358354a18a1799714e05775/diff:/var/lib/docker/overlay2/4adb98e6ab0914beb11f1320799a778f185cc6c0fb52b8f5c3ed33fbe0b15c87/diff:/var/lib/docker/overlay2/45d1ce7f2bf8ee6dde77818a560db7ab56e5dc7e105c4e547d4ddb7afec45bb7/diff:/var/lib/docker/overlay2/125b9f44f74046b514a742c42ae4b15d2801221d77ca755b4fe2bea9e4f6ea04/diff:/var/lib/docker/overlay2/68e614dae22c001828f50f78a18b16ca707861a7048b4a8d6e45ebff9a6dd450/diff:/var/lib/docker/overlay2/6f28490bb5ecd9b53c40222f342ce8d8aa6f7d3d86cc2fd5c8cefa00555cd41b/diff:/var/lib/docker/overlay2/aee2797b75a972a43792ac847518443b79a7ad9b0cb2c58913c876aa67561914/diff:/var/lib/docker/overlay2/e567e3ff35714aad9aaf45a8144dcf0216651c169099334202a3632b9a304e8d/diff:/var/lib/docker/overlay2/4b6fa679cc3dded60de622570b3fcab8ee421c6d49e07bc9412bac39ed4d122a/diff:/var/lib/docker/overlay2/6ee0ad7fd34d067f3933d749c2b33abaadd664dc55c3b01c0d287898810efe43/diff:/var/lib/docker/overlay2/24eae1670a778f5198c5ae42409b44a7cf984199b99a7807c86966b40d003d34/diff:/var/lib/docker/overlay2/4c5d5305560eb2cba1df16c7fcf7a92829a615919c82fae87546fa28b2f2300c/diff:/var/lib/docker/overlay2/0e9b0085e371589018ba910008bbb513e53f95486b4d665e6e5c1aacdd80e03f/diff:/var/lib/docker/overlay2/7cded285939312f0931e0b0421808533855c4c4afb3a567802cfdf16d9f8b395/diff", "MergedDir": "/var/lib/docker/overlay2/4aa3a69fa2f16c000a71def7040e64b630d998938cd6d1821b60a02e899d50de/merged", "UpperDir": "/var/lib/docker/overlay2/4aa3a69fa2f16c000a71def7040e64b630d998938cd6d1821b60a02e899d50de/diff", "WorkDir": "/var/lib/docker/overlay2/4aa3a69fa2f16c000a71def7040e64b630d998938cd6d1821b60a02e899d50de/work" }, "Name": "overlay2" }, ...
|
获得overlay2 最后container layer目录, /var/lib/docker/overlay2/4aa3a69fa2f16c000a71def7040e64b630d998938cd6d1821b60a02e899d50de/
进入merged/opt/blackduck/hub/hub-scan/lib
得到scan.standalone.jar
国内查看评论需要代理~