# Simple Reverse - 0x20(2023 Lab - WinMalware - Extract Next Stage Payload - 2)
## Background
* [CreateToolhelp32Snapshot](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot)
* [Process32FirstW](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-process32firstw)
* [GetCurrentProcess](https://learn.microsoft.com/zh-tw/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess)
* [OpenProcess](https://learn.microsoft.com/zh-tw/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess)
* [EqualSid](https://learn.microsoft.com/zh-tw/windows/win32/api/securitybaseapi/nf-securitybaseapi-equalsid)
* [Process32NextW](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-process32nextw)
* [OpenProcessToken](https://learn.microsoft.com/zh-tw/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken)
* [GetTokenInformation](https://learn.microsoft.com/zh-tw/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation)
## Source code
* sub_1400016B0
:::spoiler IDA Source Code解析前
```cpp
__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
1. 首先,他先利用`CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)`把當前系統中所有的process都snapshot,並回傳指定快照集的開啟控制碼(handle)
2. 在[MSDN](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot#parameters)中有提到
> 若要列舉process,請參閱 [Process32FirstW](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-process32firstw)
所以的確,該function底下就有使用到這個API(#27),主要目的是擷取系統snapshot中所遇到的第一個process相關資訊
3. 接著進到`sub_140001500`中看一下,如果不看其他exception handler的話其實蠻簡單的
1. 也就是他會先取得`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一個空間,做後續的操作

2. 再次呼叫GetTokenInformation 取得資料,此時因為我們已經明確知道需要多大的空間了,所以就不會再報錯了,此時才能真正的取得資料

3. 將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;
}
}
```
:::
4. 回到`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
簡略流程如下:
1. snapshot目前所有的process
2. 取得目前執行這支程式(A)的User SID
3. 遍歷snapshot中所有的process,如果遍歷的process(B)的User SID和剛剛取得的一樣就再memcmp,看目前的這支程式(B)是不是msedge.exe,如果是就回傳PID,若否就再遍歷下一個process(B')
:::