Пожалуйста, обратите внимание, что пользователь заблокирован
В продолжение темы atavism. Сугубо для первертов. С помощью ml.64 и его CTL (Compile Time Language) реализовал PoC для этого алгоритма хэширования строк с доступом к хешам из С или С++ модулей. Реализовать PRNG для констант const1, hash в масмовском CTL не удалось. Не нашел какой-либо информации по поддержке @Date, или каких-нибудь других подходящих функций. Может быть есть сведущие люди, кто знает как решить проблему. Компилировалось все это дело в Visual Studio.
Код:
comment "types & libs, all in one place"
include \masm32\include64\masm64rt.inc
comment "constant definitions"
comment "_HASH_API is a main struct which stores hash values"
_HASH_API struct
self qword ? ;stores address of the struct
hash1 dword ?
hash2 dword ?
hash3 dword ?
hash4 dword ?
_HASH_API ends
PHASH_API typedef PTR _HASH_API
HASH_API typedef _HASH_API
.const
;nothing here yet
;data section starts here
.data
comment "TODO: Create a PRNG macro for hash value if it's possible"
comment "This macro produce hash from API name"
HashAPIName macro apiStr
const1 = 0AB10F29Fh ;change this value if you want
;to generate new hashes
hash = 35h ;same as previous
;hash loop, obviously
forc char, apiStr
hash = hash + ((hash * const1 + '&char') and 0FFFFFFh)
endm
exitm <hash>
endm
comment "Apply macro to the needed API calls"
dw_CreateThreadHash dword HashAPIName(<CreateThread>)
dw_CreateProcessHash dword HashAPIName(<CreateProcess>)
dw_Privet dword HashAPIName(<Privet>)
dw_MessageBoxHash dword HashAPIName(<MessageBox>)
;add more if you need
;initialize struct fields
p_HashApiTable _HASH_API {0,0,0,0,0}
;code section starts here
.code
comment "This function fills the table with our hashes, which we will reference later from c/cpp code"
public FillAPIHashTable
FillAPIHashTable proc
STACKFRAME
lea rdx, [p_HashApiTable]
mov p_HashApiTable.self, rdx
mov edx, dw_CreateThreadHash
mov p_HashApiTable.hash1, edx
mov edx, dw_CreateProcessHash
mov p_HashApiTable.hash2, edx
mov edx, dw_Privet
mov p_HashApiTable.hash3, edx
mov edx, dw_MessageBoxHash
mov p_HashApiTable.hash4, edx
mov rax, p_HashApiTable.self
ret
FillAPIHashTable endp
C:
#include <Windows.h>
#include <stdio.h>
#include <winnt.h>
#include <WinDef.h>
//prototypes
PDWORD GetFunctionAddressByHash(char* library, DWORD hash);
extern PHASH_API FillAPIHashTable();
//i don't understand how to get access to the same struct from asm file
//so I just dublicate it ;D
typedef struct _HASH_API
{
UINT64 self;
UINT32 dw_CreateThreadHash;
UINT32 dw_CreateProcessHash;
UINT32 dw_Privet;
UINT32 dw_MessageBoxHash;
} HASH_API, *PHASH_API;
typedef HANDLE (__stdcall* CUSTOMCREATETHREAD)(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
__drv_aliasesMem LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
}
//credits: https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware
void main()
{
//i changed original code here and add stack strings to avoid strings search
char k32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2','\0'};
char u32[] = { 'u', 's', 'e', 'r', '3', '2', '\0' };
PHASH_API hapi;
hapi = FillAPIHashTable();
PDWORD functionAddress = GetFunctionAddressByHash(k32, hapi->dw_CreateThreadHash);
CUSTOMCREATETHREAD CreateThread = (CUSTOMCREATETHREAD)functionAddress;
DWORD tid = 0;
//call CreateThread
HANDLE th = CreateThread(NULL, NULL, NULL, NULL, NULL, &tid);
return 1;
}
DWORD GetHashFromString(char* string)
{
size_t stringLength = strnlen_s(string, 50);
DWORD hash = 0x35;
for (size_t i = 0; i < stringLength; i++)
{
hash += (hash * 0xab10f29f + string[i]) & 0xffffff;
}
//printf("%s: 0x00%x\n", string, hash);
return hash;
}
PDWORD GetFunctionAddressByHash(char* library, DWORD hash)
{
PDWORD functionAddress = (PDWORD)0;
//get base address of the module in which our exported function of interest resides (kernel32 in the case of CreateThread)
HMODULE hmlibraryBase = LoadLibraryA(library);
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hmlibraryBase;
PIMAGE_NT_HEADERS imageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)hmlibraryBase + dosHeader->e_lfanew);
DWORD_PTR exportDirectoryRVA = imageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
PIMAGE_EXPORT_DIRECTORY imageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)hmlibraryBase + exportDirectoryRVA);
//get RVAs to exported function related information
PDWORD addresOfFunctionsRVA = (PDWORD)((DWORD_PTR)hmlibraryBase + imageExportDirectory->AddressOfFunctions);
PDWORD addressOfNamesRVA = (PDWORD)((DWORD_PTR)hmlibraryBase + imageExportDirectory->AddressOfNames);
PWORD addressOfNameOrdinalsRVA = (PWORD)((DWORD_PTR)hmlibraryBase + imageExportDirectory->AddressOfNameOrdinals);
//iterate through exported functions, calculate their hashes and check if any of them match our hash of 0x00544e304 (CreateThread)
//if yes, get its virtual memory address (this is where CreateThread function resides in memory of our process)
for (DWORD i = 0; i < imageExportDirectory->NumberOfFunctions; i++)
{
DWORD functionNameRVA = addressOfNamesRVA[i];
DWORD_PTR functionNameVA = (DWORD_PTR)hmlibraryBase + functionNameRVA;
char* functionName = (char*)functionNameVA;
DWORD_PTR functionAddressRVA = 0;
//calculate hash for this exported function
DWORD functionNameHash = GetHashFromString(functionName);
//if hash for CreateThread is found, resolve the function address
if (functionNameHash == hash)
{
functionAddressRVA = addresOfFunctionsRVA[addressOfNameOrdinalsRVA[i]];
functionAddress = (PDWORD)((DWORD_PTR)hmlibraryBase + functionAddressRVA);
printf("%s : 0x%x : %p\n", functionName, functionNameHash, functionAddress);
return functionAddress;
}
}
}