Just do not use CRT and do not use imported functions.
#pragma comment(linker, "/entry:start") int start() { return 42; }
To use the WinAPI functions, find the kernel base32, analyze its export directory and find the LoadLibrary () function (you should already have something like GetProcAddress () to find LoadLibrary ())
It might look like this:
// compile as console application, "release" configuration with /MT /GS- #include <Windows.h> #pragma comment(linker, "/entry:start") void start() { HMODULE kernel32base = *(HMODULE*)(*(DWORD*)(*(DWORD*)(*(DWORD*)(*(DWORD*)(__readfsdword(0x30) + 0x0C) + 0x14))) + 0x10); DWORD base = (DWORD)kernel32base; IMAGE_NT_HEADERS* pe = PIMAGE_NT_HEADERS(base + PIMAGE_DOS_HEADER(base)->e_lfanew); IMAGE_EXPORT_DIRECTORY* exportDir = PIMAGE_EXPORT_DIRECTORY(base + pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); DWORD* namePtr = (DWORD*)(base + exportDir->AddressOfNames); WORD* ordPtr = (WORD*)(base + exportDir->AddressOfNameOrdinals); for(; strcmp((const char*)(base + *namePtr), "GetProcAddress"); ++namePtr, ++ordPtr) ; DWORD funcRVA = *(DWORD*)(base + exportDir->AddressOfFunctions + *ordPtr * 4); typedef FARPROC (WINAPI *GetProcAddress_t)(HMODULE, const char*); GetProcAddress_t GetProcAddress = (GetProcAddress_t)(base + funcRVA); HANDLE (WINAPI *GetStdHandle)(DWORD); *(FARPROC*)&GetStdHandle = GetProcAddress(kernel32base, "GetStdHandle"); HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE); BOOL (WINAPI *WriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED); *(FARPROC*)&WriteFile = GetProcAddress(kernel32base, "WriteFile"); const char* greeting = "Hello world!\n"; DWORD written; WriteFile(stdout, greeting, strlen(greeting), &written, NULL); }
source share