Simple Reverse - 0x20(2023 Lab - WinMalware - Extract Next Stage Payload - 2)
Background
- CreateToolhelp32Snapshot
- Process32FirstW
- GetCurrentProcess
- OpenProcess
- EqualSid
- Process32NextW
- OpenProcessToken
- GetTokenInformation
Source code
- sub_1400016B0
:::spoiler IDA Source Code解析前
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
73
74
75
76
77
78
79
80__int64 returnTargetPid() { DWORD LastError; // eax DWORD v2; // eax WCHAR *szExeFile; // rax signed __int64 v4; // rcx WCHAR v5; // dx int v6; // eax DWORD th32ProcessID; // [rsp+20h] [rbp-288h] HANDLE hSnapshot; // [rsp+28h] [rbp-280h] HANDLE hObject; // [rsp+30h] [rbp-278h] HANDLE CurrentProcess; // [rsp+38h] [rbp-270h] PSID pSid1; // [rsp+40h] [rbp-268h] BYREF PSID pSid2; // [rsp+48h] [rbp-260h] BYREF PROCESSENTRY32W pe; // [rsp+50h] [rbp-258h] BYREF hSnapshot = CreateToolhelp32Snapshot(2u, 0); if ( hSnapshot == (HANDLE)-1i64 ) { LastError = GetLastError(); sub_140001260("CreateToolhelp32Snapshot failed with error %lu\n", LastError); return 0i64; } else { pe.dwSize = 568; if ( Process32FirstW(hSnapshot, &pe) ) { pSid2 = malloc(0x44ui64); CurrentProcess = GetCurrentProcess(); sub_140001500(CurrentProcess, &pSid2); th32ProcessID = 0; do { pSid1 = malloc(0x44ui64); hObject = OpenProcess(0x400u, 0, pe.th32ProcessID); if ( hObject ) { if ( (unsigned int)sub_140001500(hObject, &pSid1) ) { if ( EqualSid(pSid1, pSid2) ) { szExeFile = pe.szExeFile; v4 = (char *)L"msedge.exe" - (char *)pe.szExeFile; while ( 1 ) { v5 = *szExeFile; if ( *szExeFile != *(WCHAR *)((char *)szExeFile + v4) ) break; ++szExeFile; if ( !v5 ) { v6 = 0; goto LABEL_14; } } v6 = v5 < *(WCHAR *)((char *)szExeFile + v4) ? -1 : 1; LABEL_14: if ( !v6 ) th32ProcessID = pe.th32ProcessID; } free(pSid1); } CloseHandle(hObject); } } while ( !th32ProcessID && Process32NextW(hSnapshot, &pe) ); free(pSid2); CloseHandle(hSnapshot); return th32ProcessID; } else { v2 = GetLastError(); sub_140001260("Process32First failed with error %lu\n", v2); CloseHandle(hSnapshot); return 0i64; } } }:::
Recon
- 首先,他先利用
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)把當前系統中所有的process都snapshot,並回傳指定快照集的開啟控制碼(handle) - 在MSDN中有提到
若要列舉process,請參閱 Process32FirstW
所以的確,該function底下就有使用到這個API(#27),主要目的是擷取系統snapshot中所遇到的第一個process相關資訊
- 接著進到
sub_140001500中看一下,如果不看其他exception handler的話其實蠻簡單的- 也就是他會先取得
currentProcess的token handle(暫時不需要知道handle是啥),然後再取得儲存資料所需要的buffer size,這邊很tricky的地方是,在#14的地方原本是設定TokenInformationLength = 0,而後面呼叫的GetTokenInformation就一定會報錯,但他只是想知道TokenInformation的length為多少,所以當他執行完#15行之後,&TokenInformationLength會儲存Length,而我可以利用報錯error code(也就是0x7A,ERROR_INSUFFICIENT_BUFFER),進到if statement中,然後利用得到的length再malloc一個空間,做後續的操作
- 再次呼叫GetTokenInformation 取得資料,此時因為我們已經明確知道需要多大的空間了,所以就不會再報錯了,此時才能真正的取得資料
- 將User SID 複製到a2這個變數 :::spoiler ```cpp __int64 __fastcall sub_140001500(void *a1, PSID *a2) { DWORD v2; // eax DWORD v4; // eax DWORD v5; // eax DWORD LastError; // eax PSID *TokenInformation; // [rsp+30h] [rbp-28h] DWORD TokenInformationLength; // [rsp+38h] [rbp-20h] BYREF HANDLE TokenHandle; // [rsp+40h] [rbp-18h] BYREF
TokenHandle = 0i64; if ( OpenProcessToken(a1, 0x20008u, &TokenHandle) ) { TokenInformationLength = 0; GetTokenInformation(TokenHandle, TokenUser, 0i64, 0, &TokenInformationLength); if ( GetLastError() == 122 ) { TokenInformation = (PSID )malloc(TokenInformationLength); if ( TokenInformation ) { if ( GetTokenInformation( TokenHandle, TokenUser, TokenInformation, TokenInformationLength, &TokenInformationLength) ) { if ( CopySid(0x44u, *a2, *TokenInformation) ) { if ( !IsValidSid(a2) ) sub_140001260(“Sid is invalid\n”); free(TokenInformation); CloseHandle(TokenHandle); return 1i64; } else { LastError = GetLastError(); sub_140001260(“CopySid failed, %d\n”, LastError); return 0i64; } } else { v5 = GetLastError(); sub_140001260(“GetTokenInformatoin failed, %d\n”, v5); CloseHandle(TokenHandle); return 0i64; } } else { CloseHandle(TokenHandle); return 0i64; } } else { v4 = GetLastError(); sub_140001260(“GetTokenInformatoin 1 failed, %d\n”, v4); CloseHandle(TokenHandle); return 0i64; } } else { v2 = GetLastError(); sub_140001260(“OpenProcessToken failed, %d\n”, v2); return 0i64; } } ``` :::
- 也就是他會先取得
- 回到
sub_1400016B0,可以看到#33~#67是一個do_while loop,該loop就是把現在存取的process再打開(利用PID指定),並取得他的handle,然後找到該process的User SID,再去比對前一個步驟取得的User SID和現在取得的User SID有沒有一樣,如果一樣就做==#43~#57==(其實就是memcmp("msedge.exe", process’s executable file name)),他會去比對目前的這一支程式的filename是不是msedge.exe,如果這個Edge Process的User SID和目前的current User SID一樣且memcmp也回傳是,就return PID
:::info 簡略流程如下:
- snapshot目前所有的process
- 取得目前執行這支程式(A)的User SID
- 遍歷snapshot中所有的process,如果遍歷的process(B)的User SID和剛剛取得的一樣就再memcmp,看目前的這支程式(B)是不是msedge.exe,如果是就回傳PID,若否就再遍歷下一個process(B’) :::