├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── buildclean.bat
├── buildmsvc.bat
├── buildmsvc2017.bat
├── deps
└── detours
│ ├── CREDITS.TXT
│ ├── Detours Version 3.0 Build_343
│ ├── Detours.chm
│ ├── LICENSE.RTF
│ ├── Makefile
│ ├── README.TXT
│ ├── VERSION.TXT
│ ├── src
│ ├── Makefile
│ ├── creatwth.cpp
│ ├── detours.cpp
│ ├── detours.h
│ ├── detver.h
│ ├── disasm.cpp
│ ├── disolarm.cpp
│ ├── disolarm64.cpp
│ ├── disolia64.cpp
│ ├── disolx64.cpp
│ ├── disolx86.cpp
│ ├── image.cpp
│ ├── modules.cpp
│ └── uimports.cpp
│ └── system.mak
└── src
├── CMakeLists.txt
├── experiments
├── agent.py
└── unpack.py
├── hook
├── CMakeLists.txt
├── DebugStackTracer.h
├── HookingEngine.h
├── Logger.cpp
├── Logger.h
├── Memory.h
├── SharedMemoryArray.h
├── StackWalker.cpp
├── StackWalker.h
├── SyncLock.cpp
├── SyncLock.h
├── TrackedMemoryBlock.h
├── UnpackingEngine.cpp
├── UnpackingEngine.h
├── dllmain.cpp
└── ntdefs.h
└── inject
├── CMakeLists.txt
└── main.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 | *.obj
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Compiled Dynamic libraries
12 | *.so
13 | *.dylib
14 | *.dll
15 |
16 | # Fortran module files
17 | *.mod
18 |
19 | # Compiled Static libraries
20 | *.lai
21 | *.la
22 | *.a
23 | *.lib
24 |
25 | # Executables
26 | *.exe
27 | *.out
28 | *.app
29 |
30 |
31 | #msvcpp stuff
32 | *.suo
33 | *.sdf
34 | *.opensdf
35 | *.DMP
36 | *.ipch
37 | *.user
38 |
39 | */ipch/*
40 | */Debug/*
41 | */Release/*
42 | ipch/*
43 | Debug/*
44 | Release/*
45 | build/
46 | deps/detours/lib.X86/*
47 | deps/detours/bin.X86/*
48 | deps/detours/src/obj.X86/*
49 | deps/detours/include/*
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.6)
2 | project (ThePackerAttacker)
3 |
4 | # setup some required paths
5 | set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
6 | set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
7 | set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
8 |
9 | foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
10 | string( TOUPPER ${OUTPUTCONFIG} UOUTPUTCONFIG )
11 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${UOUTPUTCONFIG} "${CMAKE_CURRENT_SOURCE_DIR}/bin/${OUTPUTCONFIG}" )
12 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${UOUTPUTCONFIG} "${CMAKE_CURRENT_SOURCE_DIR}/bin/${OUTPUTCONFIG}" )
13 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${UOUTPUTCONFIG} "${CMAKE_CURRENT_SOURCE_DIR}/bin/${OUTPUTCONFIG}" )
14 | endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )
15 |
16 |
17 | # set up deps and linkers and include stuff
18 | include_directories ("src")
19 |
20 | set (DEPS_DETOURS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/detours")
21 | include_directories ("${DEPS_DETOURS_DIR}/include")
22 | link_libraries ("${DEPS_DETOURS_DIR}/lib.X86/detours.lib")
23 |
24 | if (WIN32)
25 | link_libraries ("Psapi.lib")
26 | endif()
27 |
28 |
29 | # include our sub projects
30 | add_subdirectory ("src")
31 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT PackerAttackerInject)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PackerAttacker
2 |
3 | ## Description
4 |
5 | The Packer Attacker is a generic hidden code extractor for Windows malware. It supports the following types of pacers:
6 |
7 | 1. Running from heap
8 | 2. Replaceing PE header
9 | 3. Injecting in a process
10 |
11 |
12 | The Packer Attacker is based on Microsoft Detours.
13 |
14 |
15 | ## Compilation
16 |
17 | Compile with Microsoft C++ 2010 and Detours library. You'll have two files:
18 |
19 | 1. PackerAttackerHook.dll - unpacking engine
20 | 2. PackerAttacker.exe - DLL injector that executes malware and injects PackerAttackerHook.dll
21 |
22 |
23 | ## Setting up
24 |
25 | 1. Create folder C:\dumps - all the extracted hidden code will be saved there
26 | 2. Put PackerAttacker.exe and PackerAttackerHook.dll to %PATH%
27 | 3. If it's a clean machine you're going to need MSVC++ redistributable
28 |
29 |
30 | ## Usage
31 |
32 | PackerAttacker.exe
33 |
34 | ## Misc
35 |
36 | Currently only PE EXE files are supported.
37 |
--------------------------------------------------------------------------------
/buildclean.bat:
--------------------------------------------------------------------------------
1 | @rmdir /s /q .\build >nul 2>&1
2 | @rmdir /s /q .\bin >nul 2>&1
3 | @rmdir /s /q .\deps\detours\lib.X86 >nul 2>&1
4 | @rmdir /s /q .\deps\detours\bin.X86 >nul 2>&1
5 | @rmdir /s /q .\deps\detours\src\obj.X86 >nul 2>&1
6 | @echo Cleared all build files
--------------------------------------------------------------------------------
/buildmsvc.bat:
--------------------------------------------------------------------------------
1 | @if not defined INCLUDE (
2 | echo Must be run from a "Developer Command Prompt for VS"
3 | ) else (
4 |
5 | if not exist "build" mkdir build
6 |
7 | if exist deps\\detours\\lib.X86\\detours.lib (
8 | echo NOT BUILDING Detours BECAUSE detours.lib ALREADY EXISTS.
9 | echo To force rebuild of Detours, RUN buildclean.bat
10 | cd build && cmake -G %1 Win32 ..\\ && cd ..
11 | ) else (
12 | echo BUILDING Detours BECAUSE detours.lib DOESN'T EXIST.
13 | cd deps\\detours && nmake && cd ..\\..\\build && cmake -G %1 Win32 ..\\ && cd ..
14 | )
15 |
16 | )
--------------------------------------------------------------------------------
/buildmsvc2017.bat:
--------------------------------------------------------------------------------
1 | buildmsvc.bat "Visual Studio 15 2017"
--------------------------------------------------------------------------------
/deps/detours/CREDITS.TXT:
--------------------------------------------------------------------------------
1 | ==============================================================================
2 | The following individuals have helped identify specific bugs and improvements
3 | in Detours. The entire Detours community has benefited from their help.
4 | ==============================================================================
5 |
6 | * Jay Krell: Identified error in DetourFindPayload that caused a
7 | incorrect failure when pcbData is NULL. (Build_342)
8 |
9 | * Jay Krell: Identified issue with VirtualSize == 0 files created in
10 | NT 3.1 images. (Build_339)
11 |
12 | * Igor Odnovorov: Identified an issue with the placement of the trampoline
13 | region when a function is detoured twice and the second
14 | trampoline region is outside of the +/- 2GB range of
15 | the target. (Build_337)
16 |
17 | * Jay Krell: Identified need for some programs to enumerate the
18 | address of IAT entries. (Build_336)
19 |
20 | * Calvin Hsia: Identified need for some program to change the excluded
21 | system region. (Build_336)
22 |
23 | * Adam Smith: Identified error in failure handling when VirtualProect
24 | cannot make pages executable because the Prohibit
25 | Dynamic Code Generation mitigation policy has been
26 | applied to a process. (Build_335)
27 |
28 | * Ben Faull: Identified fix to detour_alloc_region_from_lo and
29 | detour_alloc_region_from_hi that preserves ASLR entropy.
30 | (Build_334)
31 |
32 | * Shaoxiang Su: Reported errors building with Visual Studio 2015.
33 | (Build_332)
34 |
35 | * Jay Krell: Identified and resolved significant gaps in the X86, X64
36 | and IA64 disassemblers for instruction found in code,
37 | but seldom found in function prologues. (Build_331)
38 |
39 | * Allan Murphy: Identify error in rep and jmp ds: encodings. (Build_331)
40 |
41 | * Philip Bacon: Identified incorrect entry point return for pure
42 | resource-only binaries. (Build_330)
43 |
44 | * Jay Krell: Identified failure in DetourAttachEx to update nAlign.
45 | (Build_330)
46 |
47 | * Sumit Sarin: Helped debug error with packed binaries.
48 | (Build_329)
49 |
50 | * Nitya Kumar Sharma: Reported bug in DetourAfterWithDll for 32/64 agnostic
51 | EXEs.
52 | (Build_327)
53 |
54 | * Richard Black: Identified a large number of typos in documentation.
55 | (Build_326)
56 |
57 | * Michael Bilodeau: Identified bug in DetourUpdateProcessWithDll when the
58 | target process contains a Detours payload *after* all
59 | valid PE binaries.
60 | (Build_324)
61 |
62 | * Meera Jindal: Reported bug in identification of target address in
63 | DetourCopyInstruction for jmp[] and call[] on x86 & x64,
64 | the ff15 and ff25 opcodes.
65 | (Build_323)
66 |
67 | * Ken Johnson: Assistance with SAL 2.0 annotations.
68 | (Build_319)
69 |
70 | * Nick Wood: Identified bug in DetourFindFunction on ARM.
71 | (Build_314)
72 |
73 | * Mark Russinovich: Helped debug DetourCreateProcessWithDllEx.
74 | (Build_314)
75 |
76 | * John Lin: Implementation idea for DetoursCreateProcessWithDllEx.
77 | (Build_314)
78 |
79 | * Andrew Zawadowskiy Reported an improper memory page permissions
80 | vulnerability in Detours 2.1. (Vulnerability does not
81 | exist in versions later than Detours 2.1.)
82 | (Build_223)
83 |
84 | * Nightxie: Identified bug in detour_alloc_round_up_to_region.
85 | (Build_310)
86 |
87 | * Diana Milirud: Identified bug in B* instructions on ARM.
88 | (Build_309)
89 |
90 | * Juan Carlos Identified correct MSIL entry point for unsigned MSIL.
91 | Luciani: (Build_308)
92 |
93 | * Lee Hunt Suggested improvements in algorithm for allocation of
94 | Lawrence Landauer trampoline regions on x64 to avoid collisions with
95 | Joe Laughlin: system DLLs.
96 | (Build_307)
97 |
98 | * Tyler Sims Identified bug in handling of "anycpu" MSIL binaries
99 | Darren Kennedy: on x64.
100 | (Build_307)
101 |
102 | * Andre Vachon: Help with optimized binaries.
103 | (Build 301)
104 |
105 | * Chris Mann: Identified fix not forward ported from 2.2 to 3.0.
106 | (Build_301)
107 |
108 | * Mark Irving: Identified bug with EXEs missing second import table.
109 | (Build_300)
110 |
111 | * Ben Schwarz: Identified bug in handling of multi-byte NOPs.
112 | (Build_300)
113 |
114 | * Aaron Giles Coded initial ARM/Thumb2 disassembler.
115 | Jared Henderson: (Build_300)
116 |
117 | * Doug Brubacher: Coded initial x86 disassembler.
118 | (Build_100)
119 |
--------------------------------------------------------------------------------
/deps/detours/Detours Version 3.0 Build_343:
--------------------------------------------------------------------------------
1 | Detours Version 3.0 Build_343
2 |
--------------------------------------------------------------------------------
/deps/detours/Detours.chm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BromiumLabs/PackerAttacker/24294220bf1d74146a9bf7a37c9de19230c182d5/deps/detours/Detours.chm
--------------------------------------------------------------------------------
/deps/detours/LICENSE.RTF:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg1252\deff0\deflang1033\deflangfe1041{\fonttbl{\f0\fswiss\fprq2\fcharset0 Arial;}}
2 | {\colortbl ;\red0\green0\blue255;}
3 | {\*\generator Msftedit 5.41.21.2508;}\viewkind4\uc1\pard\qc\b\i\f0\fs22 Microsoft Research Shared Source License Agreement\par
4 | (Non-commercial Use Only)\par
5 | \pard\brdrl\brdrdash\brdrw15\brsp80 \brdrt\brdrdash\brdrw15\brsp80 \brdrr\brdrdash\brdrw15 \brdrb\brdrdash\brdrw15\brsp80 \sb100\sa100 Detours 3.0 Express\par
6 | \pard\b0\i0 ______________________________________________________________________\par
7 | \pard\qj This Microsoft Research Shared Source license agreement ("MSR-SSLA") is a legal agreement between you and Microsoft Corporation (\ldblquote Microsoft\rdblquote or \ldblquote we\rdblquote ) for the software or data identified above, which may include source code, and any associated materials, text or speech files, associated media and "online" or electronic documentation and any updates we provide in our discretion (together, the "Software").\par
8 | \par
9 | \pard By installing, copying, or otherwise using this Software, found at http://research.microsoft.com/downloads, you agree to be bound by the terms of this MSR-SSLA. If you do not agree, do not install copy or use the Software. The Software is protected by copyright and other intellectual property laws and is licensed, not sold.\par
10 | \strike\par
11 | \pard\sb100\sa100\qj\b\strike0 SCOPE OF RIGHTS:\par
12 | \b0 You may use, copy, reproduce, and distribute this Software for any non-commercial purpose, subject to the restrictions in this MSR-SSLA. Some purposes which can be non-commercial are teaching, academic research, public demonstrations and personal experimentation. You may also distribute this Software with books or other teaching materials, or publish the Software on websites, that are intended to teach the use of the Software for academic or other non-commercial purposes.\par
13 | You may not use or distribute this Software or any derivative works in any form for commercial purposes. Examples of commercial purposes would be running business operations, licensing, leasing, or selling the Software, distributing the Software for use with commercial products, using the Software in the creation or use of commercial products or any other activity which purpose is to procure a commercial gain to you or others.\par
14 | If the Software includes source code or data, you may create derivative works of such portions of the Software and distribute the modified Software for non-commercial purposes, as provided herein.\par
15 | \line In return, we simply require that you agree:\par
16 | \pard\fi-360\li720\sb100\sa240\qj\tx720 1.\tab That you will not remove any copyright or other notices from the Software.\par
17 | 2.\tab That if any of the Software is in binary format, you will not attempt to modify such portions of the Software, or to reverse engineer or decompile them, except and only to the extent authorized by applicable law.\par
18 | 3.\tab That if you distribute the Software or any derivative works of the Software, you will distribute them under the same terms and conditions as in this license, and you will not grant other rights to the Software or derivative works that are different from those provided by this MSR-SSLA.\par
19 | 4.\tab That if you have created derivative works of the Software, and distribute such derivative works, you will cause the modified files to carry prominent notices so that recipients know that they are not receiving the original Software. Such notices must state: (i) that you have changed the Software; and (ii) the date of any changes.\par
20 | 5.\tab That Microsoft is granted back, without any restrictions or limitations, a non-exclusive, perpetual, irrevocable, royalty-free, assignable and sub-licensable license, to reproduce, publicly perform or display, install, use, modify, distribute, make and have made, sell and transfer your modifications to and/or derivative works of the Software source code or data, for any purpose. .\par
21 | 6.\tab That any feedback about the Software provided by you to us is voluntarily given, and Microsoft shall be free to use the feedback as it sees fit without obligation or restriction of any kind, even if the feedback is designated by you as confidential. \par
22 | 7.\tab THAT THE SOFTWARE COMES "AS IS", WITH NO WARRANTIES. THIS MEANS NO EXPRESS, IMPLIED OR STATUTORY WARRANTY, INCLUDING WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE,\caps any warranty against interference with your enjoyment of the Software \caps0 OR ANY WARRANTY OF TITLE OR NON-INFRINGEMENT. \caps There is no warranty that this Software will fulfill any of your particular purposes or needs\caps0 . ALSO, YOU MUST PASS THIS DISCLAIMER ON WHENEVER YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS.\par
23 | 8.\tab THAT NEITHER MICROSOFT NOR ANY CONTRIBUTOR TO THE SOFTWARE WILL BE LIABLE FOR ANY DAMAGES RELATED TO THE SOFTWARE OR THIS MSR-SSLA, INCLUDING DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL OR INCIDENTAL DAMAGES, TO THE MAXIMUM EXTENT THE LAW PERMITS, NO MATTER WHAT LEGAL THEORY IT IS BASED ON. ALSO, YOU MUST PASS THIS LIMITATION OF LIABILITY ON WHENEVER YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS.\par
24 | 9.\tab That we have no duty of reasonable care or lack of negligence, and we are not obligated to (and will not) provide technical support for the Software.\par
25 | 10.\tab That if you breach this MSR-SSLA or if you sue anyone over patents that you think may apply to or read on the Software or anyone's use of the Software, this MSR-SSLA (and your license and rights obtained herein) terminate automatically. Upon any such termination, you shall destroy all of your copies of the Software immediately. Sections 5, 6, 7, 8, 9, 10, 13 and 14 of this MSR-SSLA shall survive any termination of this MSR-SSLA.\par
26 | 11.\tab That the patent rights, if any, granted to you in this MSR-SSLA only apply to the Software, not to any derivative works you make.\par
27 | 12.\tab That the Software may be subject to U.S. export jurisdiction at the time it is licensed to you, and it may be subject to additional export or import laws in other places.\~ You agree to comply with all such laws and regulations that may apply to the Software after delivery of the software to you.\par
28 | \pard\fi-360\li720\sb100\sa100\qj\tx720 13.\tab That all rights not expressly granted to you in this MSR-SSLA are reserved.\par
29 | 14.\tab That this MSR-SSLA shall be construed and controlled by the laws of the State of Washington, USA, without regard to conflicts of law. If any provision of this MSR-SSLA shall be deemed unenforceable or contrary to law, the rest of this MSR-SSLA shall remain in full effect and interpreted in an enforceable manner that most nearly captures the intent of the original language. \par
30 | \pard\li360\sb100\sa100\qj\par
31 | \pard\qj\i Copyright (c) Microsoft Corporation. All rights reserved.\par
32 | \par
33 | Do you accept all of the terms of the preceding MSR-SSLA license agreement? If you accept the terms, click \ldblquote I Agree,\rdblquote then \ldblquote Next.\rdblquote Otherwise click \ldblquote Cancel.\rdblquote\par
34 | \i0\par
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/deps/detours/Makefile:
--------------------------------------------------------------------------------
1 | ##############################################################################
2 | ##
3 | ## Makefile for Detours.
4 | ##
5 | ## Microsoft Research Detours Package, Version 3.0.
6 | ##
7 | ## Copyright (c) Microsoft Corporation. All rights reserved.
8 | ##
9 |
10 | ROOT = .
11 | !include "$(ROOT)\system.mak"
12 |
13 | all:
14 | cd "$(MAKEDIR)"
15 | @if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS)
16 | cd "$(MAKEDIR)\src"
17 | @$(MAKE) /NOLOGO /$(MAKEFLAGS)
18 | cd "$(MAKEDIR)"
19 |
20 | clean:
21 | cd "$(MAKEDIR)"
22 | @if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean
23 | cd "$(MAKEDIR)\src"
24 | @$(MAKE) /NOLOGO /$(MAKEFLAGS) clean
25 | cd "$(MAKEDIR)"
26 |
27 | realclean: clean
28 | cd "$(MAKEDIR)"
29 | @if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
30 | cd "$(MAKEDIR)\src"
31 | @$(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
32 | cd "$(MAKEDIR)"
33 | -rmdir /q /s $(INCDS) 2> nul
34 | -rmdir /q /s $(LIBDS) 2> nul
35 | -rmdir /q /s $(BINDS) 2> nul
36 | -rmdir /q /s dist 2> nul
37 | -del docsrc\detours.chm 2> nul
38 | -del /q *.msi 2>nul
39 | -del /q /f /s *~ 2>nul
40 |
41 | test:
42 | cd "$(MAKEDIR)"
43 |
44 | ################################################################# End of File.
45 |
--------------------------------------------------------------------------------
/deps/detours/README.TXT:
--------------------------------------------------------------------------------
1 | Microsoft Research Detours Package
2 | Detours Version 3.0 Build_343
3 |
4 | DISCLAIMER AND LICENSE:
5 | =======================
6 | The entire Detours package is covered by copyright law.
7 | Copyright (c) Microsoft Corporation. All rights reserved.
8 | Portions are covered by patents owned by Microsoft Corporation.
9 |
10 | Usage of the Detours package is covered under the End User License Agreement.
11 | Your usage of Detours implies your acceptance of the End User License Agreement.
12 |
13 | Detours 3.0 Professional, which includes rights to use Detours in commerical
14 | products and production use is available through the online Microsoft Store:
15 | http://www.microsoftstore.com/store/msstore/en_US/pd/productID.216531800
16 |
17 |
18 | 1. INTRODUCTION:
19 | ================
20 | This document describes the installation and usage of this version of the
21 | Detours package. In particular, it provides an updated API table.
22 |
23 | Complete documentation for the Detours package, including a detailed API
24 | reference can be found in the Detours.chm file.
25 |
26 |
27 | 2. BUILD INSTRUCTIONS:
28 | ======================
29 | If you installed Detours under the "Program Files" directory, copy the entire
30 | contents of the detours directory to some other location where your account
31 | has write access before attempting to build.
32 |
33 | To build the libraries and the sample applications, type "nmake" in the
34 | root directory of your Detours distribution.
35 |
36 | If you are using Detours for the first time, a good practice is to start
37 | by modifying one of the samples that is closest to your desired usage.
38 |
39 |
40 | 3. VERIFYING THE INSTALL AND BUILD:
41 | ===================================
42 | After building the libraries and sample applications, you can verify that
43 | the Detours packet works on your Windows OS by typing "nmake test" in the
44 | samples\slept directory. The output of "namke test" should be similar
45 | to that contained in the file samples\slept\NORMAL.TXT.
46 |
47 |
48 | 4. CHANGES IN VERSION 3.0:
49 | ==========================
50 | The following major changes were made in Detours 3.0 from Detours 2.x:
51 | * Support for scenarios that mix both 32-bit and 64-bit processes.
52 | * Support for ARM processors (in addition to support for X86, X64, and IA64).
53 | * Removal of the detoured.dll marker binary.
54 | * Compatibility improvements, especially on x64 processors.
55 | * Addition of APIs to enumerate PE binary Imports and to determine the
56 | module referenced by a function pointer.
57 | * Improved support for highly-optimized code on X64 processors.
58 | * Improved support for detouring hot-patchable binaries.
59 | * Improved algorithm for allocation of trampolines.
60 |
61 |
62 | 4.1. SUPPORT FOR MIXING 32-BIT AND 64-BIT PROCESSES:
63 | ====================================================
64 | Previous version of Detours only supported pure 64-bit or pure 32-bit
65 | environments. Detours 3.0 includes support for creating parallel 32-bit
66 | and 64-bit DLLs that can be loaded dynamically into target processes with
67 | Detours automatically selecting the correct architectur DLL. The
68 | DetourCreateProcessWithDllEx function selects the correct DLL based on
69 | the word size (32-bit or 64-bit) of the target process. For more
70 | information see the "Detouring 32-bit and 64-bit Processes" section of
71 | the Detours documentation (Detours.chm).
72 |
73 |
74 | 4.2. ARM SUPPORT:
75 | =================
76 | Detours 3.0 includes support for detouring functions on ARM processors
77 | using the Thumb-2 instruction set.
78 |
79 |
80 | 4.3. REMOVAL OF DETOURED.DLL:
81 | =============================
82 | Products shipping with Detours 3.0 no longer need to include detoured.dll
83 | in their dependencies. Prior to Detours 3.0, Detours loaded the detoured.dll
84 | shared library stub into any process which was modified by the insertion of
85 | a detour. This allowed the Microsoft Customer Support Services (CSS) and the
86 | Microsoft Online Crash Analysis (OCA) teams to quickly and accurately
87 | determine that the behavior of a process has been altered by a detour.
88 | Microsoft does not provide customer assistance on detoured products.
89 |
90 | With Detours 3.0, detoured.dll has been removed. Advances in recent versions
91 | of Windows allow CSS and OCA to accurately track third-party code that has
92 | been loaded into a process, thus removing the need for detoured.dll. One
93 | side effect of this change is that the path to the detoured.dll is no longer
94 | provided as an argument to DetourCreateProcessWithDll, reducing it's argument
95 | count by one.
96 |
97 |
98 | 4.4. COMPATIBILITY IMPROVEMENTS:
99 | ================================
100 | Fixes have been made in Detours 3.0 to improve support for target binaries
101 | containing no DLL imports, DLL binaries compiled for online-patching,
102 | binaries generated with hot-patching support, and 64-bit PE binaries
103 | containing managed code.
104 |
105 |
106 | 4.5. APIS TO ENUMERATE PE BINARY IMPORTS:
107 | =========================================
108 | Added DetourEnumerateImports API to enumerate the functions imported by a
109 | EXE or DLL. Given a pointer to a function, the DetourGetContainingModule
110 | API will return the HMODULE of the binary within which it resides.
111 |
112 |
113 | 4.6. TRANSACTIONAL MODEL AND THREAD UPDATE:
114 | ===========================================
115 | Typically, a developer uses the Detours package to detour a family of
116 | functions. Race conditions can be introduced into the detour code as the
117 | target functions are detoured one by one. Also, the developer typically
118 | wants a error model in which all target functions are detoured entirely or
119 | none of the target functions are detoured if a particular function can't be
120 | detoured. In previous version of Detours, programmers either ignored
121 | these race and error conditions, or attempted to avoid them by carefully
122 | timing the insertion and deletion of detours.
123 |
124 | To simplify the development model, Detours 3.0 uses a transactional model for
125 | attaching and detaching detours. Your code should call DetourTransactionBegin
126 | to begin a transaction, issue a group of DetourAttach or DetourDetach calls to
127 | affect the desired target functions, call DetourUpdateThread to mark threads
128 | which may be affected by the updates, and then call
129 | DetourTransactionCommit to complete the operation.
130 |
131 | When DetourTransactionCommit is called, Detours suspends all effected
132 | threads (except the calling thread), insert or removes the detours as
133 | specified, updates the program counter for any threads that were running
134 | inside the affected functions, then resumes the affected threads. If an error
135 | occurs during the transaction, or if DetourTransactioAbort is called, Detours
136 | safely aborts all of the operations within the transaction. From the perspective
137 | of all threads marks marked for update, the entire transaction is atomic,
138 | either all threads and functions are modified, or none are modified.
139 |
140 |
141 | 4.7. 64-BIT SUPPORT:
142 | ====================
143 | Detours includes support for 64-bit execution on X64 and IA64 processors.
144 | Detours understands the new 64-bit instructions of the X64 and IA64 and can
145 | detour 64-bit code when used in a 64-bit process.
146 |
147 |
148 | 4.8. ALLOCATION OF TRAMPOLINES:
149 | ===============================
150 | To intercept calls, Detours copies the first few instructions of the target
151 | function into a block of memory called a trampoline. In previous versions
152 | of Detours, trampolines were allocated a close as possible to the target
153 | code. In some cases, the trampoline memory would conflict with later
154 | DLL loads in the same process. This would hurt performance by causing
155 | later DLLs to be dynamically rebased. Detours 3.0 includes a new algorithm
156 | for allocating trampolines. The new algorithm attempts to place trampolines
157 | roughly 1GB above or below the target code in the address space.
158 |
159 |
160 | 5. API SUMMARY:
161 | ===============
162 |
163 | 5.1. APIS FOR DETOURING TARGET FUNCTIONS:
164 | =========================================
165 | DetourTransactionBegin() - Begin a new detour transaction.
166 |
167 | DetourUpdateThread() - Mark a thread that should be included in the
168 | current detour transaction.
169 |
170 | DetourAttach() - Attach a detour to a target function as part
171 | of the current detour transaction.
172 |
173 | DetourAttachEx() - Attach a detour to a target function and
174 | retrieved additional detail about the ultimate
175 | target as part of the current detour transaction.
176 |
177 | DetourDetach() - Detach a detour from a target function as part
178 | of the current detour transaction.
179 |
180 | DetourSetIgnoreTooSmall() - Set the flag to determine if failure to detour
181 | a target function that is too small for detouring
182 | is sufficient error to cause abort of the current
183 | detour transaction.
184 |
185 | DetourTransactionAbort() - Abort the current detour transaction.
186 |
187 | DetourTransactionCommit() - Attempt to commit the current detour transaction.
188 |
189 | DetourTransactionCommitEx() - Attempt to commit the current transaction, if
190 | transaction fails, retrieve error information.
191 |
192 |
193 | 5.2. APIS FOR FINDING TARGETS:
194 | ==============================
195 | DetourFindFunction() - Tries to retrieve a function pointer for a named
196 | function through the dynamic linking export
197 | tables for the named module and then, if that
198 | fails, through debugging symbols if available.
199 |
200 | DetourCodeFromPointer() - Given a function pointer, returns a pointer to the
201 | code implementing the function. Skips over extra
202 | code often inserted by linkers or compilers for
203 | cross-DLL calls.
204 |
205 |
206 | 5.3. APIS FOR FINDING ACCESSING LOADED BINARIES AND PAYLOADS:
207 | =============================================================
208 | DetourEnumerateModules() - Enumerates all of the PE binaries loaded into a
209 | process.
210 |
211 | DetourGetContainingModule() - Return the module containing a function.
212 |
213 | DetourGetEntryPoint() - Returns a pointer the entry point for a module.
214 |
215 | DetourGetModuleSize() - Returns the load size of a module.
216 |
217 | DetourEnumerateExports() - Enumerates all exports from a module.
218 |
219 | DetourEnumerateImports() - Enumerates all import dependencies of a module.
220 |
221 | DetourFindPayload() - Finds the address of the specified payload
222 | within a module.
223 |
224 | DetourFindPayloadEx() - Finds the specified payload if it exists anywhere
225 | in the process.
226 |
227 | DetourGetSizeOfPayloads() - Returns the size of all payloads within a
228 | module.
229 |
230 |
231 | 5.4. APIS FOR MODIFYING BINARIES:
232 | =================================
233 | DetourBinaryOpen() - Open a binary for in-memory update.
234 |
235 | DetourBinaryEnumeratePayloads() - Enumerats all of the payloads in a binary.
236 |
237 | DetourBinaryFindPayload() - Finds a specific payload within a binary.
238 |
239 | DetourBinarySetPayload() - Attaches a payload to a binary.
240 |
241 | DetourBinaryDeletePayload() - Removes a payload from a binary.
242 |
243 | DetourBinaryPurgePayloads() - Removes all payloads from a binary.
244 |
245 | DetourBinaryEditImports() - Edits the import tables of a binary.
246 |
247 | DetourBinaryResetImports() - Removes all edits to the import tables of a
248 | binary including any edits made by previous
249 | programs using the Detours package.
250 |
251 | DetourBinaryWrite() - Writes the updated binary to a file.
252 |
253 | DetourBinaryClose() - Release the in-memory updates for a binary.
254 |
255 | DetourBinaryBind() - Binds the DLL imports for a named binary file.
256 |
257 |
258 | 5.5. APIS FOR INSERTING DLLS INTO PROCESSES:
259 | ============================================
260 | DetourCreateProcessWithDll() - Creates a new process with the specified
261 | DLL inserted into it.
262 |
263 | DetourCreateProcessWithDllEx() - Creates a new process with a DLL inserted,
264 | selecting a 32-bit DLL for a 32-bit target
265 | process or a 64-bit DLL for a 64-bit target
266 | process.
267 |
268 | DetourRestoreAfterWith() - Restores the contents of the in memory import
269 | table after a process was started with
270 | DetourCreateProcessWithDll.
271 |
272 | DetourIsHelperProcess() - Determines if a DLL is being loaded by rundll32
273 | in a helper process in order to make the
274 | transition from a 32-bit process to a 64-bit
275 | process or from a 64-bit process to a 32-bit
276 | process.
277 |
278 | DetourFinishHelperProcess() - Completes the operations of a helper process.
279 |
280 |
281 | 6. COMPATIBILITY:
282 | =================
283 | All Detours functions are compatible with all versions of Microsoft Windows
284 | Operating Systems with the supported service packs installed. This includes
285 | Windows XP, Windows Server 2003, Windows Server 2003 R2, Windows Vista,
286 | Windows Server 2008, Windows 7, Windows Server 2008 R2, and Windows 8.
287 |
288 |
289 | 7. MANIFEST:
290 | ============
291 | The Detours package consists of the Detours library source code and a number
292 | of sample programs. Descriptions of the sample programs can be found in
293 | the help file.
294 |
295 |
296 | 8. NOTES:
297 | =========
298 | When writing detour functions, it is imperative that the binary-calling
299 | convention of the detour and trampoline functions match exactly the
300 | binary-calling convention of the target function.
301 |
302 | In a few cases, when the sizeof() a return value is smaller than sizeof(int),
303 | C or C++ compilers will generate non-compatible binary-calling conventions by
304 | not widening the return value to an int as is customary for small return values.
305 | The result is a syntactically-identical, but not binary-compatible, detour
306 | function. In most cases, the problem can be fixed be having the detour function
307 | return a value widened to a sizeof(int) type. Developers are urged to exercise
308 | caution, and should insure that correct code is generated by their C or C++
309 | compiler for detour functions with small return values.
310 |
311 | When attaching a DLL to a binary with Detours DLL import APIs, the DLL must
312 | export one procedure with export ordinal 1. The exported procedure is not
313 | called by the application, but it used as the import target.
314 |
315 | Detours requires a compiler compatible with Visual C++.NET or later.
316 |
317 |
318 | 9. BUG REPORTS:
319 | ===============
320 | Please send detailed bug reports to detours@microsoft.com. Submitted bug
321 | reports may be used to fix bugs in future versions of the Detours package.
322 | Please include the text "DETOURS BUG REPORT" in the subject line. Please
323 | also include the first line of this README.TXT file containing the full
324 | version description information. The detours@microsoft.com email address
325 | is not a product support line.
326 |
--------------------------------------------------------------------------------
/deps/detours/VERSION.TXT:
--------------------------------------------------------------------------------
1 | Detours Version 3.0 Build_343
2 |
--------------------------------------------------------------------------------
/deps/detours/src/Makefile:
--------------------------------------------------------------------------------
1 | ##############################################################################
2 | ##
3 | ## Makefile for Detours.
4 | ##
5 | ## Microsoft Research Detours Package, Version 3.0 Build_343.
6 | ##
7 | ## Copyright (c) Microsoft Corporation. All rights reserved.
8 | ##
9 |
10 | ROOT = ..
11 | !include "$(ROOT)\system.mak"
12 |
13 | !IF "$(DETOURS_SOURCE_BROWSING)" == ""
14 | DETOURS_SOURCE_BROWSING = 0
15 | !ENDIF
16 |
17 | #######################/#######################################################
18 | ##
19 | CFLAGS=/W4 /WX /Zi /MT /Gy /Gm- /Zl /Od
20 |
21 | !IF $(DETOURS_SOURCE_BROWSING)==1
22 | CFLAGS=$(CFLAGS) /FR
23 | !ELSE
24 | CFLAGS=$(CFLAGS) /DWIN32_LEAN_AND_MEAN /D_WIN32_WINNT=0x501
25 | !ENDIF
26 |
27 | !IF "$(DETOURS_TARGET_PROCESSOR)" == "IA64"
28 | CFLAGS=$(CFLAGS) /wd4163 # intrinsic rdtebex not available; using newer Windows headers with older compiler
29 | !ENDIF
30 |
31 | !if defined(DETOURS_WIN_7) && defined(DETOURS_CL_17_OR_NEWER)
32 | CFLAGS=$(CFLAGS) /D_USING_V110_SDK71_
33 | !elseif defined(DETOURS_ANALYZE)
34 | CFLAGS=$(CFLAGS) /analyze
35 | !endif
36 |
37 | OBJS = \
38 | $(OBJD)\detours.obj \
39 | $(OBJD)\modules.obj \
40 | $(OBJD)\disasm.obj \
41 | $(OBJD)\image.obj \
42 | $(OBJD)\creatwth.obj \
43 | $(OBJD)\disolx86.obj \
44 | $(OBJD)\disolx64.obj \
45 | $(OBJD)\disolia64.obj \
46 | $(OBJD)\disolarm.obj \
47 | $(OBJD)\disolarm64.obj \
48 |
49 | ##############################################################################
50 | ##
51 | .SUFFIXES: .cpp .h .obj
52 |
53 | !ifdef DETOURS_ANALYZE
54 | .cpp{$(OBJD)}.obj:
55 | $(CC) $(CFLAGS) /Fd$(LIBD)\detours.pdb /Fo$(OBJD)\ /c $<
56 | !else
57 | .cpp{$(OBJD)}.obj::
58 | $(CC) $(CFLAGS) /Fd$(LIBD)\detours.pdb /Fo$(OBJD)\ /c $<
59 | !endif
60 |
61 | ##############################################################################
62 |
63 | all: dirs \
64 | $(LIBD)\detours.lib \
65 | $(INCD)\detours.h \
66 | $(INCD)\detver.h \
67 | !IF $(DETOURS_SOURCE_BROWSING)==1
68 | $(OBJD)\detours.bsc \
69 | !endif
70 |
71 | ##############################################################################
72 |
73 | clean:
74 | -del *~ 2>nul
75 | -del $(LIBD)\detours.pdb $(LIBD)\detours.lib 2>nul
76 | -rmdir /q /s $(OBJD) 2>nul
77 |
78 | realclean: clean
79 | -rmdir /q /s $(OBJDS) 2>nul
80 |
81 | ##############################################################################
82 |
83 | dirs:
84 | @if not exist "$(INCD)" mkdir "$(INCD)" && echo. Created $(INCD)
85 | @if not exist "$(LIBD)" mkdir "$(LIBD)" && echo. Created $(LIBD)
86 | @if not exist "$(BIND)" mkdir "$(BIND)" && echo. Created $(BIND)
87 | @if not exist "$(OBJD)" mkdir "$(OBJD)" && echo. Created $(OBJD)
88 |
89 | $(OBJD)\detours.bsc : $(OBJS)
90 | bscmake /v /n /o $@ $(OBJS:.obj=.sbr)
91 |
92 | $(LIBD)\detours.lib : $(OBJS)
93 | link /lib /out:$@ $(OBJS)
94 |
95 | $(INCD)\detours.h : detours.h
96 | copy detours.h $@
97 |
98 | $(INCD)\detver.h : detver.h
99 | copy detver.h $@
100 |
101 | $(OBJD)\detours.obj : detours.cpp detours.h
102 | $(OBJD)\modules.obj : modules.cpp detours.h
103 | $(OBJD)\disasm.obj : disasm.cpp detours.h
104 | $(OBJD)\image.obj : image.cpp detours.h
105 | $(OBJD)\creatwth.obj : creatwth.cpp uimports.cpp detours.h
106 | $(OBJD)\disolx86.obj: disasm.cpp detours.h
107 | $(OBJD)\disolx64.obj: disasm.cpp detours.h
108 | $(OBJD)\disolia64.obj: disasm.cpp detours.h
109 | $(OBJD)\disolarm.obj: disasm.cpp detours.h
110 | $(OBJD)\disolarm64.obj: disasm.cpp detours.h
111 |
112 | test: all
113 | cd $(MAKEDIR)\..\samples\slept
114 | nmake /nologo test
115 | cd $(MAKEDIR)
116 |
117 | ################################################################# End of File.
118 |
--------------------------------------------------------------------------------
/deps/detours/src/detver.h:
--------------------------------------------------------------------------------
1 | //////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Common version parameters.
4 | //
5 | // Microsoft Research Detours Package, Version 3.0 Build_343.
6 | //
7 | // Copyright (c) Microsoft Corporation. All rights reserved.
8 | //
9 |
10 | #define _USING_V110_SDK71_ 1
11 | #include "winver.h"
12 | #if 0
13 | #include
14 | #include
15 | #else
16 | #ifndef DETOURS_STRINGIFY
17 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x)
18 | #define DETOURS_STRINGIFY_(x) #x
19 | #endif
20 |
21 | #define VER_FILEFLAGSMASK 0x3fL
22 | #define VER_FILEFLAGS 0x0L
23 | #define VER_FILEOS 0x00040004L
24 | #define VER_FILETYPE 0x00000002L
25 | #define VER_FILESUBTYPE 0x00000000L
26 | #endif
27 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS)
28 |
--------------------------------------------------------------------------------
/deps/detours/src/disolarm.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_ARM_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/deps/detours/src/disolarm64.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_ARM64_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/deps/detours/src/disolia64.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_IA64_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/deps/detours/src/disolx64.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_X64_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/deps/detours/src/disolx86.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_X86_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/deps/detours/src/modules.cpp:
--------------------------------------------------------------------------------
1 | //////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Module Enumeration Functions (modules.cpp of detours.lib)
4 | //
5 | // Microsoft Research Detours Package, Version 3.0 Build_343.
6 | //
7 | // Copyright (c) Microsoft Corporation. All rights reserved.
8 | //
9 | // Module enumeration functions.
10 | //
11 |
12 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1
13 |
14 | #pragma warning(disable:4068) // unknown pragma (suppress)
15 |
16 | #if _MSC_VER >= 1900
17 | #pragma warning(push)
18 | #pragma warning(disable:4091) // empty typedef
19 | #endif
20 |
21 | #define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1
22 | #include
23 | #if (_MSC_VER < 1310)
24 | #else
25 | #pragma warning(push)
26 | #if _MSC_VER > 1400
27 | #pragma warning(disable:6102 6103) // /analyze warnings
28 | #endif
29 | #include
30 | #pragma warning(pop)
31 | #endif
32 |
33 | // #define DETOUR_DEBUG 1
34 | #define DETOURS_INTERNAL
35 | #include "detours.h"
36 |
37 | #if DETOURS_VERSION != 30001
38 | #error detours.h version mismatch
39 | #endif
40 |
41 | #if _MSC_VER >= 1900
42 | #pragma warning(pop)
43 | #endif
44 |
45 | #define CLR_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
46 | #define IAT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]
47 |
48 | //////////////////////////////////////////////////////////////////////////////
49 | //
50 | const GUID DETOUR_EXE_RESTORE_GUID = {
51 | 0x2ed7a3ff, 0x3339, 0x4a8d,
52 | { 0x80, 0x5c, 0xd4, 0x98, 0x15, 0x3f, 0xc2, 0x8f }};
53 |
54 | //////////////////////////////////////////////////////////////////////////////
55 | //
56 | PDETOUR_SYM_INFO DetourLoadImageHlp(VOID)
57 | {
58 | static DETOUR_SYM_INFO symInfo;
59 | static PDETOUR_SYM_INFO pSymInfo = NULL;
60 | static BOOL failed = false;
61 |
62 | if (failed) {
63 | return NULL;
64 | }
65 | if (pSymInfo != NULL) {
66 | return pSymInfo;
67 | }
68 |
69 | ZeroMemory(&symInfo, sizeof(symInfo));
70 | // Create a real handle to the process.
71 | #if 0
72 | DuplicateHandle(GetCurrentProcess(),
73 | GetCurrentProcess(),
74 | GetCurrentProcess(),
75 | &symInfo.hProcess,
76 | 0,
77 | FALSE,
78 | DUPLICATE_SAME_ACCESS);
79 | #else
80 | symInfo.hProcess = GetCurrentProcess();
81 | #endif
82 |
83 | symInfo.hDbgHelp = LoadLibraryExW(L"dbghelp.dll", NULL, 0);
84 | if (symInfo.hDbgHelp == NULL) {
85 | abort:
86 | failed = true;
87 | if (symInfo.hDbgHelp != NULL) {
88 | FreeLibrary(symInfo.hDbgHelp);
89 | }
90 | symInfo.pfImagehlpApiVersionEx = NULL;
91 | symInfo.pfSymInitialize = NULL;
92 | symInfo.pfSymSetOptions = NULL;
93 | symInfo.pfSymGetOptions = NULL;
94 | symInfo.pfSymLoadModule64 = NULL;
95 | symInfo.pfSymGetModuleInfo64 = NULL;
96 | symInfo.pfSymFromName = NULL;
97 | return NULL;
98 | }
99 |
100 | symInfo.pfImagehlpApiVersionEx
101 | = (PF_ImagehlpApiVersionEx)GetProcAddress(symInfo.hDbgHelp,
102 | "ImagehlpApiVersionEx");
103 | symInfo.pfSymInitialize
104 | = (PF_SymInitialize)GetProcAddress(symInfo.hDbgHelp, "SymInitialize");
105 | symInfo.pfSymSetOptions
106 | = (PF_SymSetOptions)GetProcAddress(symInfo.hDbgHelp, "SymSetOptions");
107 | symInfo.pfSymGetOptions
108 | = (PF_SymGetOptions)GetProcAddress(symInfo.hDbgHelp, "SymGetOptions");
109 | symInfo.pfSymLoadModule64
110 | = (PF_SymLoadModule64)GetProcAddress(symInfo.hDbgHelp, "SymLoadModule64");
111 | symInfo.pfSymGetModuleInfo64
112 | = (PF_SymGetModuleInfo64)GetProcAddress(symInfo.hDbgHelp, "SymGetModuleInfo64");
113 | symInfo.pfSymFromName
114 | = (PF_SymFromName)GetProcAddress(symInfo.hDbgHelp, "SymFromName");
115 |
116 | API_VERSION av;
117 | ZeroMemory(&av, sizeof(av));
118 | av.MajorVersion = API_VERSION_NUMBER;
119 |
120 | if (symInfo.pfImagehlpApiVersionEx == NULL ||
121 | symInfo.pfSymInitialize == NULL ||
122 | symInfo.pfSymLoadModule64 == NULL ||
123 | symInfo.pfSymGetModuleInfo64 == NULL ||
124 | symInfo.pfSymFromName == NULL) {
125 | goto abort;
126 | }
127 |
128 | symInfo.pfImagehlpApiVersionEx(&av);
129 | if (av.MajorVersion < API_VERSION_NUMBER) {
130 | goto abort;
131 | }
132 |
133 | if (!symInfo.pfSymInitialize(symInfo.hProcess, NULL, FALSE)) {
134 | // We won't retry the initialize if it fails.
135 | goto abort;
136 | }
137 |
138 | if (symInfo.pfSymGetOptions != NULL && symInfo.pfSymSetOptions != NULL) {
139 | DWORD dw = symInfo.pfSymGetOptions();
140 |
141 | dw &= ~(SYMOPT_CASE_INSENSITIVE |
142 | SYMOPT_UNDNAME |
143 | SYMOPT_DEFERRED_LOADS |
144 | 0);
145 | dw |= (
146 | #if defined(SYMOPT_EXACT_SYMBOLS)
147 | SYMOPT_EXACT_SYMBOLS |
148 | #endif
149 | #if defined(SYMOPT_NO_UNQUALIFIED_LOADS)
150 | SYMOPT_NO_UNQUALIFIED_LOADS |
151 | #endif
152 | SYMOPT_DEFERRED_LOADS |
153 | #if defined(SYMOPT_FAIL_CRITICAL_ERRORS)
154 | SYMOPT_FAIL_CRITICAL_ERRORS |
155 | #endif
156 | #if defined(SYMOPT_INCLUDE_32BIT_MODULES)
157 | SYMOPT_INCLUDE_32BIT_MODULES |
158 | #endif
159 | 0);
160 | symInfo.pfSymSetOptions(dw);
161 | }
162 |
163 | pSymInfo = &symInfo;
164 | return pSymInfo;
165 | }
166 |
167 | PVOID WINAPI DetourFindFunction(_In_ PCSTR pszModule,
168 | _In_ PCSTR pszFunction)
169 | {
170 | /////////////////////////////////////////////// First, try GetProcAddress.
171 | //
172 | #pragma prefast(suppress:28752, "We don't do the unicode conversion for LoadLibraryExA.")
173 | HMODULE hModule = LoadLibraryExA(pszModule, NULL, 0);
174 | if (hModule == NULL) {
175 | return NULL;
176 | }
177 |
178 | PBYTE pbCode = (PBYTE)GetProcAddress(hModule, pszFunction);
179 | if (pbCode) {
180 | return pbCode;
181 | }
182 |
183 | ////////////////////////////////////////////////////// Then try ImageHelp.
184 | //
185 | DETOUR_TRACE(("DetourFindFunction(%hs, %hs)\n", pszModule, pszFunction));
186 | PDETOUR_SYM_INFO pSymInfo = DetourLoadImageHlp();
187 | if (pSymInfo == NULL) {
188 | DETOUR_TRACE(("DetourLoadImageHlp failed: %d\n",
189 | GetLastError()));
190 | return NULL;
191 | }
192 |
193 | if (pSymInfo->pfSymLoadModule64(pSymInfo->hProcess, NULL,
194 | (PCHAR)pszModule, NULL,
195 | (DWORD64)hModule, 0) == 0) {
196 | if (ERROR_SUCCESS != GetLastError()) {
197 | DETOUR_TRACE(("SymLoadModule64(%p) failed: %d\n",
198 | pSymInfo->hProcess, GetLastError()));
199 | return NULL;
200 | }
201 | }
202 |
203 | HRESULT hrRet;
204 | CHAR szFullName[512];
205 | IMAGEHLP_MODULE64 modinfo;
206 | ZeroMemory(&modinfo, sizeof(modinfo));
207 | modinfo.SizeOfStruct = sizeof(modinfo);
208 | if (!pSymInfo->pfSymGetModuleInfo64(pSymInfo->hProcess, (DWORD64)hModule, &modinfo)) {
209 | DETOUR_TRACE(("SymGetModuleInfo64(%p, %p) failed: %d\n",
210 | pSymInfo->hProcess, hModule, GetLastError()));
211 | return NULL;
212 | }
213 |
214 | hrRet = StringCchCopyA(szFullName, sizeof(szFullName)/sizeof(CHAR), modinfo.ModuleName);
215 | if (FAILED(hrRet)) {
216 | DETOUR_TRACE(("StringCchCopyA failed: %08x\n", hrRet));
217 | return NULL;
218 | }
219 | hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), "!");
220 | if (FAILED(hrRet)) {
221 | DETOUR_TRACE(("StringCchCatA failed: %08x\n", hrRet));
222 | return NULL;
223 | }
224 | hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), pszFunction);
225 | if (FAILED(hrRet)) {
226 | DETOUR_TRACE(("StringCchCatA failed: %08x\n", hrRet));
227 | return NULL;
228 | }
229 |
230 | struct CFullSymbol : SYMBOL_INFO {
231 | CHAR szRestOfName[512];
232 | } symbol;
233 | ZeroMemory(&symbol, sizeof(symbol));
234 | //symbol.ModBase = (ULONG64)hModule;
235 | symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
236 | #ifdef DBHLPAPI
237 | symbol.MaxNameLen = sizeof(symbol.szRestOfName)/sizeof(symbol.szRestOfName[0]);
238 | #else
239 | symbol.MaxNameLength = sizeof(symbol.szRestOfName)/sizeof(symbol.szRestOfName[0]);
240 | #endif
241 |
242 | if (!pSymInfo->pfSymFromName(pSymInfo->hProcess, szFullName, &symbol)) {
243 | DETOUR_TRACE(("SymFromName(%hs) failed: %d\n", szFullName, GetLastError()));
244 | return NULL;
245 | }
246 |
247 | #if defined(DETOURS_IA64)
248 | // On the IA64, we get a raw code pointer from the symbol engine
249 | // and have to convert it to a wrapped [code pointer, global pointer].
250 | //
251 | PPLABEL_DESCRIPTOR pldEntry = (PPLABEL_DESCRIPTOR)DetourGetEntryPoint(hModule);
252 | PPLABEL_DESCRIPTOR pldSymbol = new PLABEL_DESCRIPTOR;
253 |
254 | pldSymbol->EntryPoint = symbol.Address;
255 | pldSymbol->GlobalPointer = pldEntry->GlobalPointer;
256 | return (PBYTE)pldSymbol;
257 | #elif defined(DETOURS_ARM)
258 | // On the ARM, we get a raw code pointer, which we must convert into a
259 | // valied Thumb2 function pointer.
260 | return DETOURS_PBYTE_TO_PFUNC(symbol.Address);
261 | #else
262 | return (PBYTE)symbol.Address;
263 | #endif
264 | }
265 |
266 | //////////////////////////////////////////////////// Module Image Functions.
267 | //
268 |
269 | HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast)
270 | {
271 | PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY;
272 |
273 | MEMORY_BASIC_INFORMATION mbi;
274 | ZeroMemory(&mbi, sizeof(mbi));
275 |
276 | // Find the next memory region that contains a mapped PE image.
277 | //
278 | for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
279 | if (VirtualQuery(pbLast, &mbi, sizeof(mbi)) <= 0) {
280 | break;
281 | }
282 |
283 | // Skip uncommitted regions and guard pages.
284 | //
285 | if ((mbi.State != MEM_COMMIT) ||
286 | ((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
287 | (mbi.Protect & PAGE_GUARD)) {
288 | continue;
289 | }
290 |
291 | __try {
292 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbLast;
293 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ||
294 | (DWORD)pDosHeader->e_lfanew > mbi.RegionSize ||
295 | (DWORD)pDosHeader->e_lfanew < sizeof(*pDosHeader)) {
296 | continue;
297 | }
298 |
299 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
300 | pDosHeader->e_lfanew);
301 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
302 | continue;
303 | }
304 |
305 | return (HMODULE)pDosHeader;
306 | }
307 | #pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.")
308 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
309 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
310 | continue;
311 | }
312 | }
313 | return NULL;
314 | }
315 |
316 | PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule)
317 | {
318 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
319 | if (hModule == NULL) {
320 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
321 | }
322 |
323 | __try {
324 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
325 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
326 | SetLastError(ERROR_BAD_EXE_FORMAT);
327 | return NULL;
328 | }
329 |
330 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
331 | pDosHeader->e_lfanew);
332 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
333 | SetLastError(ERROR_INVALID_EXE_SIGNATURE);
334 | return NULL;
335 | }
336 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
337 | SetLastError(ERROR_EXE_MARKED_INVALID);
338 | return NULL;
339 | }
340 |
341 | PDETOUR_CLR_HEADER pClrHeader = NULL;
342 | if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
343 | if (((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.VirtualAddress != 0 &&
344 | ((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.Size != 0) {
345 | pClrHeader = (PDETOUR_CLR_HEADER)
346 | (((PBYTE)pDosHeader)
347 | + ((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.VirtualAddress);
348 | }
349 | }
350 | else if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
351 | if (((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.VirtualAddress != 0 &&
352 | ((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.Size != 0) {
353 | pClrHeader = (PDETOUR_CLR_HEADER)
354 | (((PBYTE)pDosHeader)
355 | + ((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.VirtualAddress);
356 | }
357 | }
358 |
359 | if (pClrHeader != NULL) {
360 | // For MSIL assemblies, we want to use the _Cor entry points.
361 |
362 | HMODULE hClr = GetModuleHandleW(L"MSCOREE.DLL");
363 | if (hClr == NULL) {
364 | return NULL;
365 | }
366 |
367 | SetLastError(NO_ERROR);
368 | return GetProcAddress(hClr, "_CorExeMain");
369 | }
370 |
371 | SetLastError(NO_ERROR);
372 |
373 | // Pure resource DLLs have neither an entry point nor CLR information
374 | // so handle them by returning NULL (LastError is NO_ERROR)
375 | if (pNtHeader->OptionalHeader.AddressOfEntryPoint == 0) {
376 | return NULL;
377 | }
378 |
379 | return ((PBYTE)pDosHeader) +
380 | pNtHeader->OptionalHeader.AddressOfEntryPoint;
381 | }
382 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
383 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
384 | SetLastError(ERROR_EXE_MARKED_INVALID);
385 | return NULL;
386 | }
387 | }
388 |
389 | ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule)
390 | {
391 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
392 | if (hModule == NULL) {
393 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
394 | }
395 |
396 | __try {
397 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
398 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
399 | SetLastError(ERROR_BAD_EXE_FORMAT);
400 | return NULL;
401 | }
402 |
403 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
404 | pDosHeader->e_lfanew);
405 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
406 | SetLastError(ERROR_INVALID_EXE_SIGNATURE);
407 | return NULL;
408 | }
409 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
410 | SetLastError(ERROR_EXE_MARKED_INVALID);
411 | return NULL;
412 | }
413 | SetLastError(NO_ERROR);
414 |
415 | return (pNtHeader->OptionalHeader.SizeOfImage);
416 | }
417 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
418 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
419 | SetLastError(ERROR_EXE_MARKED_INVALID);
420 | return NULL;
421 | }
422 | }
423 |
424 | HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr)
425 | {
426 | MEMORY_BASIC_INFORMATION mbi;
427 | ZeroMemory(&mbi, sizeof(mbi));
428 |
429 | __try {
430 | if (VirtualQuery(pvAddr, &mbi, sizeof(mbi)) <= 0) {
431 | SetLastError(ERROR_BAD_EXE_FORMAT);
432 | return NULL;
433 | }
434 |
435 | // Skip uncommitted regions and guard pages.
436 | //
437 | if ((mbi.State != MEM_COMMIT) ||
438 | ((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
439 | (mbi.Protect & PAGE_GUARD)) {
440 | SetLastError(ERROR_BAD_EXE_FORMAT);
441 | return NULL;
442 | }
443 |
444 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
445 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
446 | SetLastError(ERROR_BAD_EXE_FORMAT);
447 | return NULL;
448 | }
449 |
450 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
451 | pDosHeader->e_lfanew);
452 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
453 | SetLastError(ERROR_INVALID_EXE_SIGNATURE);
454 | return NULL;
455 | }
456 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
457 | SetLastError(ERROR_EXE_MARKED_INVALID);
458 | return NULL;
459 | }
460 | SetLastError(NO_ERROR);
461 |
462 | return (HMODULE)pDosHeader;
463 | }
464 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
465 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
466 | SetLastError(ERROR_INVALID_EXE_SIGNATURE);
467 | return NULL;
468 | }
469 | }
470 |
471 |
472 | static inline PBYTE RvaAdjust(_Pre_notnull_ PIMAGE_DOS_HEADER pDosHeader, _In_ DWORD raddr)
473 | {
474 | if (raddr != NULL) {
475 | return ((PBYTE)pDosHeader) + raddr;
476 | }
477 | return NULL;
478 | }
479 |
480 | BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule,
481 | _In_opt_ PVOID pContext,
482 | _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport)
483 | {
484 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
485 | if (hModule == NULL) {
486 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
487 | }
488 |
489 | __try {
490 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
491 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
492 | SetLastError(ERROR_BAD_EXE_FORMAT);
493 | return NULL;
494 | }
495 |
496 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
497 | pDosHeader->e_lfanew);
498 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
499 | SetLastError(ERROR_INVALID_EXE_SIGNATURE);
500 | return FALSE;
501 | }
502 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
503 | SetLastError(ERROR_EXE_MARKED_INVALID);
504 | return FALSE;
505 | }
506 |
507 | PIMAGE_EXPORT_DIRECTORY pExportDir
508 | = (PIMAGE_EXPORT_DIRECTORY)
509 | RvaAdjust(pDosHeader,
510 | pNtHeader->OptionalHeader
511 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
512 |
513 | if (pExportDir == NULL) {
514 | SetLastError(ERROR_EXE_MARKED_INVALID);
515 | return FALSE;
516 | }
517 |
518 | PBYTE pExportDirEnd = (PBYTE)pExportDir + pNtHeader->OptionalHeader
519 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
520 | PDWORD pdwFunctions = (PDWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfFunctions);
521 | PDWORD pdwNames = (PDWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfNames);
522 | PWORD pwOrdinals = (PWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfNameOrdinals);
523 |
524 | for (DWORD nFunc = 0; nFunc < pExportDir->NumberOfFunctions; nFunc++) {
525 | PBYTE pbCode = (pdwFunctions != NULL)
526 | ? (PBYTE)RvaAdjust(pDosHeader, pdwFunctions[nFunc]) : NULL;
527 | PCHAR pszName = NULL;
528 |
529 | // if the pointer is in the export region, then it is a forwarder.
530 | if (pbCode > (PBYTE)pExportDir && pbCode < pExportDirEnd) {
531 | pbCode = NULL;
532 | }
533 |
534 | for (DWORD n = 0; n < pExportDir->NumberOfNames; n++) {
535 | if (pwOrdinals[n] == nFunc) {
536 | pszName = (pdwNames != NULL)
537 | ? (PCHAR)RvaAdjust(pDosHeader, pdwNames[n]) : NULL;
538 | break;
539 | }
540 | }
541 | ULONG nOrdinal = pExportDir->Base + nFunc;
542 |
543 | if (!pfExport(pContext, nOrdinal, pszName, pbCode)) {
544 | break;
545 | }
546 | }
547 | SetLastError(NO_ERROR);
548 | return TRUE;
549 | }
550 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
551 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
552 | SetLastError(ERROR_EXE_MARKED_INVALID);
553 | return NULL;
554 | }
555 | }
556 |
557 | BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule,
558 | _In_opt_ PVOID pContext,
559 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile,
560 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFunc)
561 | {
562 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
563 | if (hModule == NULL) {
564 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
565 | }
566 |
567 | __try {
568 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
569 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
570 | SetLastError(ERROR_BAD_EXE_FORMAT);
571 | return FALSE;
572 | }
573 |
574 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
575 | pDosHeader->e_lfanew);
576 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
577 | SetLastError(ERROR_INVALID_EXE_SIGNATURE);
578 | return FALSE;
579 | }
580 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
581 | SetLastError(ERROR_EXE_MARKED_INVALID);
582 | return FALSE;
583 | }
584 |
585 | PIMAGE_IMPORT_DESCRIPTOR iidp
586 | = (PIMAGE_IMPORT_DESCRIPTOR)
587 | RvaAdjust(pDosHeader,
588 | pNtHeader->OptionalHeader
589 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
590 |
591 | if (iidp == NULL) {
592 | SetLastError(ERROR_EXE_MARKED_INVALID);
593 | return FALSE;
594 | }
595 |
596 | for (; iidp->OriginalFirstThunk != 0; iidp++) {
597 |
598 | PCSTR pszName = (PCHAR)RvaAdjust(pDosHeader, iidp->Name);
599 | if (pszName == NULL) {
600 | SetLastError(ERROR_EXE_MARKED_INVALID);
601 | return FALSE;
602 | }
603 |
604 | PIMAGE_THUNK_DATA pThunks = (PIMAGE_THUNK_DATA)
605 | RvaAdjust(pDosHeader, iidp->OriginalFirstThunk);
606 | PVOID * pAddrs = (PVOID *)
607 | RvaAdjust(pDosHeader, iidp->FirstThunk);
608 |
609 | HMODULE hFile = DetourGetContainingModule(pAddrs[0]);
610 |
611 | if (pfImportFile != NULL) {
612 | if (!pfImportFile(pContext, hFile, pszName)) {
613 | break;
614 | }
615 | }
616 |
617 | DWORD nNames = 0;
618 | if (pThunks) {
619 | for (; pThunks[nNames].u1.Ordinal; nNames++) {
620 | DWORD nOrdinal = 0;
621 | PCSTR pszFunc = NULL;
622 |
623 | if (IMAGE_SNAP_BY_ORDINAL(pThunks[nNames].u1.Ordinal)) {
624 | nOrdinal = (DWORD)IMAGE_ORDINAL(pThunks[nNames].u1.Ordinal);
625 | }
626 | else {
627 | pszFunc = (PCSTR)RvaAdjust(pDosHeader,
628 | (DWORD)pThunks[nNames].u1.AddressOfData + 2);
629 | }
630 |
631 | if (pfImportFunc != NULL) {
632 | if (!pfImportFunc(pContext,
633 | nOrdinal,
634 | pszFunc,
635 | &pAddrs[nNames])) {
636 | break;
637 | }
638 | }
639 | }
640 | if (pfImportFunc != NULL) {
641 | pfImportFunc(pContext, 0, NULL, NULL);
642 | }
643 | }
644 | }
645 | if (pfImportFile != NULL) {
646 | pfImportFile(pContext, NULL, NULL);
647 | }
648 | SetLastError(NO_ERROR);
649 | return TRUE;
650 | }
651 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
652 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
653 | SetLastError(ERROR_EXE_MARKED_INVALID);
654 | return FALSE;
655 | }
656 | }
657 |
658 | // Context for DetourEnumerateImportsThunk, which adapts "regular" callbacks for use with "Ex".
659 | struct _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT
660 | {
661 | PVOID pContext;
662 | PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc;
663 | };
664 |
665 | // Callback for DetourEnumerateImportsEx that adapts DetourEnumerateImportsEx
666 | // for use with a DetourEnumerateImports callback -- derefence the IAT and pass the value on.
667 |
668 | static
669 | BOOL
670 | CALLBACK
671 | DetourEnumerateImportsThunk(_In_ PVOID VoidContext,
672 | _In_ DWORD nOrdinal,
673 | _In_opt_ PCSTR pszFunc,
674 | _In_opt_ PVOID* ppvFunc)
675 | {
676 | _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT const * const
677 | pContext = (_DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT*)VoidContext;
678 | return pContext->pfImportFunc(pContext->pContext, nOrdinal, pszFunc, ppvFunc ? *ppvFunc : NULL);
679 | }
680 |
681 | BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule,
682 | _In_opt_ PVOID pContext,
683 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile,
684 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc)
685 | {
686 | _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT const context = { pContext, pfImportFunc };
687 |
688 | return DetourEnumerateImportsEx(hModule,
689 | (PVOID)&context,
690 | pfImportFile,
691 | &DetourEnumerateImportsThunk);
692 | }
693 |
694 | static PDETOUR_LOADED_BINARY WINAPI GetPayloadSectionFromModule(HMODULE hModule)
695 | {
696 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
697 | if (hModule == NULL) {
698 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
699 | }
700 |
701 | __try {
702 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
703 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
704 | SetLastError(ERROR_BAD_EXE_FORMAT);
705 | return NULL;
706 | }
707 |
708 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
709 | pDosHeader->e_lfanew);
710 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
711 | SetLastError(ERROR_INVALID_EXE_SIGNATURE);
712 | return NULL;
713 | }
714 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
715 | SetLastError(ERROR_EXE_MARKED_INVALID);
716 | return NULL;
717 | }
718 |
719 | PIMAGE_SECTION_HEADER pSectionHeaders
720 | = (PIMAGE_SECTION_HEADER)((PBYTE)pNtHeader
721 | + sizeof(pNtHeader->Signature)
722 | + sizeof(pNtHeader->FileHeader)
723 | + pNtHeader->FileHeader.SizeOfOptionalHeader);
724 |
725 | for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; n++) {
726 | if (strcmp((PCHAR)pSectionHeaders[n].Name, ".detour") == 0) {
727 | if (pSectionHeaders[n].VirtualAddress == 0 ||
728 | pSectionHeaders[n].SizeOfRawData == 0) {
729 |
730 | break;
731 | }
732 |
733 | PBYTE pbData = (PBYTE)pDosHeader + pSectionHeaders[n].VirtualAddress;
734 | DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pbData;
735 | if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
736 | pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
737 |
738 | break;
739 | }
740 |
741 | if (pHeader->nDataOffset == 0) {
742 | pHeader->nDataOffset = pHeader->cbHeaderSize;
743 | }
744 | SetLastError(NO_ERROR);
745 | return (PBYTE)pHeader;
746 | }
747 | }
748 | SetLastError(ERROR_EXE_MARKED_INVALID);
749 | return NULL;
750 | }
751 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
752 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
753 | SetLastError(ERROR_EXE_MARKED_INVALID);
754 | return NULL;
755 | }
756 | }
757 |
758 | DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule)
759 | {
760 | PDETOUR_LOADED_BINARY pBinary = GetPayloadSectionFromModule(hModule);
761 | if (pBinary == NULL) {
762 | // Error set by GetPayloadSectionFromModule.
763 | return 0;
764 | }
765 |
766 | __try {
767 | DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary;
768 | if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
769 | pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
770 |
771 | SetLastError(ERROR_INVALID_HANDLE);
772 | return 0;
773 | }
774 | SetLastError(NO_ERROR);
775 | return pHeader->cbDataSize;
776 | }
777 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
778 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
779 | SetLastError(ERROR_INVALID_HANDLE);
780 | return 0;
781 | }
782 | }
783 |
784 | _Writable_bytes_(*pcbData)
785 | _Readable_bytes_(*pcbData)
786 | _Success_(return != NULL)
787 | PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
788 | _In_ REFGUID rguid,
789 | _Out_ DWORD *pcbData)
790 | {
791 | PBYTE pbData = NULL;
792 | if (pcbData) {
793 | *pcbData = 0;
794 | }
795 |
796 | PDETOUR_LOADED_BINARY pBinary = GetPayloadSectionFromModule(hModule);
797 | if (pBinary == NULL) {
798 | // Error set by GetPayloadSectionFromModule.
799 | return NULL;
800 | }
801 |
802 | __try {
803 | DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary;
804 | if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
805 | pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
806 |
807 | SetLastError(ERROR_INVALID_EXE_SIGNATURE);
808 | return NULL;
809 | }
810 |
811 | PBYTE pbBeg = ((PBYTE)pHeader) + pHeader->nDataOffset;
812 | PBYTE pbEnd = ((PBYTE)pHeader) + pHeader->cbDataSize;
813 |
814 | for (pbData = pbBeg; pbData < pbEnd;) {
815 | DETOUR_SECTION_RECORD *pSection = (DETOUR_SECTION_RECORD *)pbData;
816 |
817 | if (pSection->guid.Data1 == rguid.Data1 &&
818 | pSection->guid.Data2 == rguid.Data2 &&
819 | pSection->guid.Data3 == rguid.Data3 &&
820 | pSection->guid.Data4[0] == rguid.Data4[0] &&
821 | pSection->guid.Data4[1] == rguid.Data4[1] &&
822 | pSection->guid.Data4[2] == rguid.Data4[2] &&
823 | pSection->guid.Data4[3] == rguid.Data4[3] &&
824 | pSection->guid.Data4[4] == rguid.Data4[4] &&
825 | pSection->guid.Data4[5] == rguid.Data4[5] &&
826 | pSection->guid.Data4[6] == rguid.Data4[6] &&
827 | pSection->guid.Data4[7] == rguid.Data4[7]) {
828 |
829 | if (pcbData) {
830 | *pcbData = pSection->cbBytes - sizeof(*pSection);
831 | }
832 | SetLastError(NO_ERROR);
833 | return (PBYTE)(pSection + 1);
834 | }
835 |
836 | pbData = (PBYTE)pSection + pSection->cbBytes;
837 | }
838 | SetLastError(ERROR_INVALID_HANDLE);
839 | return NULL;
840 | }
841 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
842 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
843 | SetLastError(ERROR_INVALID_HANDLE);
844 | return NULL;
845 | }
846 | }
847 |
848 | _Writable_bytes_(*pcbData)
849 | _Readable_bytes_(*pcbData)
850 | _Success_(return != NULL)
851 | PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
852 | _Out_ DWORD * pcbData)
853 | {
854 | for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) {
855 | PVOID pvData;
856 |
857 | pvData = DetourFindPayload(hMod, rguid, pcbData);
858 | if (pvData != NULL) {
859 | return pvData;
860 | }
861 | }
862 | SetLastError(ERROR_MOD_NOT_FOUND);
863 | return NULL;
864 | }
865 |
866 | BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
867 | _In_ DWORD cbData)
868 | {
869 | PDETOUR_EXE_RESTORE pder = (PDETOUR_EXE_RESTORE)pvData;
870 |
871 | if (pder->cb != sizeof(*pder) || pder->cb > cbData) {
872 | SetLastError(ERROR_BAD_EXE_FORMAT);
873 | return FALSE;
874 | }
875 |
876 | DWORD dwPermIdh = ~0u;
877 | DWORD dwPermInh = ~0u;
878 | DWORD dwPermClr = ~0u;
879 | DWORD dwIgnore;
880 | BOOL fSucceeded = FALSE;
881 | BOOL fUpdated32To64 = FALSE;
882 |
883 | if (pder->pclr != NULL && pder->clr.Flags != ((PDETOUR_CLR_HEADER)pder->pclr)->Flags) {
884 | // If we had to promote the 32/64-bit agnostic IL to 64-bit, we can't restore
885 | // that.
886 | fUpdated32To64 = TRUE;
887 | }
888 |
889 | if (DetourVirtualProtectSameExecute(pder->pidh, pder->cbidh,
890 | PAGE_EXECUTE_READWRITE, &dwPermIdh)) {
891 | if (DetourVirtualProtectSameExecute(pder->pinh, pder->cbinh,
892 | PAGE_EXECUTE_READWRITE, &dwPermInh)) {
893 |
894 | CopyMemory(pder->pidh, &pder->idh, pder->cbidh);
895 | CopyMemory(pder->pinh, &pder->inh, pder->cbinh);
896 |
897 | if (pder->pclr != NULL && !fUpdated32To64) {
898 | if (DetourVirtualProtectSameExecute(pder->pclr, pder->cbclr,
899 | PAGE_EXECUTE_READWRITE, &dwPermClr)) {
900 | CopyMemory(pder->pclr, &pder->clr, pder->cbclr);
901 | VirtualProtect(pder->pclr, pder->cbclr, dwPermClr, &dwIgnore);
902 | fSucceeded = TRUE;
903 | }
904 | }
905 | else {
906 | fSucceeded = TRUE;
907 | }
908 | VirtualProtect(pder->pinh, pder->cbinh, dwPermInh, &dwIgnore);
909 | }
910 | VirtualProtect(pder->pidh, pder->cbidh, dwPermIdh, &dwIgnore);
911 | }
912 | return fSucceeded;
913 | }
914 |
915 | BOOL WINAPI DetourRestoreAfterWith()
916 | {
917 | PVOID pvData;
918 | DWORD cbData;
919 |
920 | pvData = DetourFindPayloadEx(DETOUR_EXE_RESTORE_GUID, &cbData);
921 |
922 | if (pvData != NULL && cbData != 0) {
923 | return DetourRestoreAfterWithEx(pvData, cbData);
924 | }
925 | SetLastError(ERROR_MOD_NOT_FOUND);
926 | return FALSE;
927 | }
928 |
929 | // End of File
930 |
--------------------------------------------------------------------------------
/deps/detours/src/uimports.cpp:
--------------------------------------------------------------------------------
1 | //////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Add DLLs to a module import table (uimports.cpp of detours.lib)
4 | //
5 | // Microsoft Research Detours Package, Version 3.0 Build_343.
6 | //
7 | // Copyright (c) Microsoft Corporation. All rights reserved.
8 | //
9 | // Note that this file is included into creatwth.cpp one or more times
10 | // (once for each supported module format).
11 | //
12 |
13 | #if DETOURS_VERSION != 30001
14 | #error detours.h version mismatch
15 | #endif
16 |
17 | // UpdateImports32 aka UpdateImports64
18 | static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
19 | HMODULE hModule,
20 | __in_ecount(nDlls) LPCSTR *plpDlls,
21 | DWORD nDlls)
22 | {
23 | BOOL fSucceeded = FALSE;
24 | DWORD cbNew = 0;
25 |
26 | BYTE * pbNew = NULL;
27 | DWORD i;
28 | SIZE_T cbRead;
29 | DWORD n;
30 |
31 | PBYTE pbModule = (PBYTE)hModule;
32 |
33 | IMAGE_DOS_HEADER idh;
34 | ZeroMemory(&idh, sizeof(idh));
35 | if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), &cbRead)
36 | || cbRead < sizeof(idh)) {
37 |
38 | DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n",
39 | pbModule, pbModule + sizeof(idh), GetLastError()));
40 |
41 | finish:
42 | if (pbNew != NULL) {
43 | delete[] pbNew;
44 | pbNew = NULL;
45 | }
46 | return fSucceeded;
47 | }
48 |
49 | IMAGE_NT_HEADERS_XX inh;
50 | ZeroMemory(&inh, sizeof(inh));
51 |
52 | if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), &cbRead)
53 | || cbRead < sizeof(inh)) {
54 | DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n",
55 | pbModule + idh.e_lfanew,
56 | pbModule + idh.e_lfanew + sizeof(inh),
57 | GetLastError()));
58 | goto finish;
59 | }
60 |
61 | if (inh.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC_XX) {
62 | DETOUR_TRACE(("Wrong size image (%04x != %04x).\n",
63 | inh.OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC_XX));
64 | SetLastError(ERROR_INVALID_BLOCK);
65 | goto finish;
66 | }
67 |
68 | // Zero out the bound table so loader doesn't use it instead of our new table.
69 | inh.BOUND_DIRECTORY.VirtualAddress = 0;
70 | inh.BOUND_DIRECTORY.Size = 0;
71 |
72 | // Find the size of the mapped file.
73 | DWORD dwSec = idh.e_lfanew +
74 | FIELD_OFFSET(IMAGE_NT_HEADERS_XX, OptionalHeader) +
75 | inh.FileHeader.SizeOfOptionalHeader;
76 |
77 | for (i = 0; i < inh.FileHeader.NumberOfSections; i++) {
78 | IMAGE_SECTION_HEADER ish;
79 | ZeroMemory(&ish, sizeof(ish));
80 |
81 | if (!ReadProcessMemory(hProcess, pbModule + dwSec + sizeof(ish) * i, &ish,
82 | sizeof(ish), &cbRead)
83 | || cbRead < sizeof(ish)) {
84 |
85 | DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %d\n",
86 | pbModule + dwSec + sizeof(ish) * i,
87 | pbModule + dwSec + sizeof(ish) * (i + 1),
88 | GetLastError()));
89 | goto finish;
90 | }
91 |
92 | DETOUR_TRACE(("ish[%d] : va=%08x sr=%d\n", i, ish.VirtualAddress, ish.SizeOfRawData));
93 |
94 | // If the file didn't have an IAT_DIRECTORY, we assign it...
95 | if (inh.IAT_DIRECTORY.VirtualAddress == 0 &&
96 | inh.IMPORT_DIRECTORY.VirtualAddress >= ish.VirtualAddress &&
97 | inh.IMPORT_DIRECTORY.VirtualAddress < ish.VirtualAddress + ish.SizeOfRawData) {
98 |
99 | inh.IAT_DIRECTORY.VirtualAddress = ish.VirtualAddress;
100 | inh.IAT_DIRECTORY.Size = ish.SizeOfRawData;
101 | }
102 | }
103 |
104 | DETOUR_TRACE((" Imports: %p..%p\n",
105 | (DWORD_PTR)pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
106 | (DWORD_PTR)pbModule + inh.IMPORT_DIRECTORY.VirtualAddress +
107 | inh.IMPORT_DIRECTORY.Size));
108 |
109 | DWORD nOldDlls = inh.IMPORT_DIRECTORY.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
110 | DWORD obRem = sizeof(IMAGE_IMPORT_DESCRIPTOR) * nDlls;
111 | DWORD obOld = obRem + sizeof(IMAGE_IMPORT_DESCRIPTOR) * nOldDlls;
112 | DWORD obTab = PadToDwordPtr(obOld);
113 | DWORD obDll = obTab + sizeof(DWORD_XX) * 4 * nDlls;
114 | DWORD obStr = obDll;
115 | cbNew = obStr;
116 | for (n = 0; n < nDlls; n++) {
117 | cbNew += PadToDword((DWORD)strlen(plpDlls[n]) + 1);
118 | }
119 |
120 | _Analysis_assume_(cbNew >
121 | sizeof(IMAGE_IMPORT_DESCRIPTOR) * (nDlls + nOldDlls)
122 | + sizeof(DWORD_XX) * 4 * nDlls);
123 | pbNew = new BYTE [cbNew];
124 | if (pbNew == NULL) {
125 | DETOUR_TRACE(("new BYTE [cbNew] failed.\n"));
126 | goto finish;
127 | }
128 | ZeroMemory(pbNew, cbNew);
129 |
130 | PBYTE pbBase = pbModule;
131 | PBYTE pbNext = pbBase
132 | + inh.OptionalHeader.BaseOfCode
133 | + inh.OptionalHeader.SizeOfCode
134 | + inh.OptionalHeader.SizeOfInitializedData
135 | + inh.OptionalHeader.SizeOfUninitializedData;
136 | if (pbBase < pbNext) {
137 | pbBase = pbNext;
138 | }
139 | DETOUR_TRACE(("pbBase = %p\n", pbBase));
140 |
141 | PBYTE pbNewIid = FindAndAllocateNearBase(hProcess, pbBase, cbNew);
142 | if (pbNewIid == NULL) {
143 | DETOUR_TRACE(("FindAndAllocateNearBase failed.\n"));
144 | goto finish;
145 | }
146 |
147 | PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew;
148 | DWORD_XX *pt;
149 |
150 | DWORD obBase = (DWORD)(pbNewIid - pbModule);
151 | DWORD dwProtect = 0;
152 |
153 | if (inh.IMPORT_DIRECTORY.VirtualAddress != 0) {
154 | // Read the old import directory if it exists.
155 | DETOUR_TRACE(("IMPORT_DIRECTORY perms=%x\n", dwProtect));
156 |
157 | if (!ReadProcessMemory(hProcess,
158 | pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
159 | &piid[nDlls],
160 | nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR), &cbRead)
161 | || cbRead < nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR)) {
162 |
163 | DETOUR_TRACE(("ReadProcessMemory(imports) failed: %d\n", GetLastError()));
164 | goto finish;
165 | }
166 | }
167 |
168 | for (n = 0; n < nDlls; n++) {
169 | HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]);
170 | if (FAILED(hrRet)) {
171 | DETOUR_TRACE(("StringCchCopyA failed: %d\n", GetLastError()));
172 | goto finish;
173 | }
174 |
175 | // After copying the string, we patch up the size "??" bits if any.
176 | hrRet = ReplaceOptionalSizeA((char*)pbNew + obStr,
177 | cbNew - obStr,
178 | DETOURS_STRINGIFY(DETOURS_BITS_XX));
179 | if (FAILED(hrRet)) {
180 | DETOUR_TRACE(("ReplaceOptionalSizeA failed: %d\n", GetLastError()));
181 | goto finish;
182 | }
183 |
184 | DWORD nOffset = obTab + (sizeof(DWORD_XX) * (4 * n));
185 | piid[n].OriginalFirstThunk = obBase + nOffset;
186 | pt = ((DWORD_XX*)(pbNew + nOffset));
187 | pt[0] = IMAGE_ORDINAL_FLAG_XX + 1;
188 | pt[1] = 0;
189 |
190 | nOffset = obTab + (sizeof(DWORD_XX) * ((4 * n) + 2));
191 | piid[n].FirstThunk = obBase + nOffset;
192 | pt = ((DWORD_XX*)(pbNew + nOffset));
193 | pt[0] = IMAGE_ORDINAL_FLAG_XX + 1;
194 | pt[1] = 0;
195 | piid[n].TimeDateStamp = 0;
196 | piid[n].ForwarderChain = 0;
197 | piid[n].Name = obBase + obStr;
198 |
199 | obStr += PadToDword((DWORD)strlen(plpDlls[n]) + 1);
200 | }
201 | _Analysis_assume_(obStr <= cbNew);
202 |
203 | #if 0
204 | for (i = 0; i < nDlls + nOldDlls; i++) {
205 | DETOUR_TRACE(("%8d. Look=%08x Time=%08x Fore=%08x Name=%08x Addr=%08x\n",
206 | i,
207 | piid[i].OriginalFirstThunk,
208 | piid[i].TimeDateStamp,
209 | piid[i].ForwarderChain,
210 | piid[i].Name,
211 | piid[i].FirstThunk));
212 | if (piid[i].OriginalFirstThunk == 0 && piid[i].FirstThunk == 0) {
213 | break;
214 | }
215 | }
216 | #endif
217 |
218 | if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) {
219 | DETOUR_TRACE(("WriteProcessMemory(iid) failed: %d\n", GetLastError()));
220 | goto finish;
221 | }
222 |
223 | DETOUR_TRACE(("obBaseBef = %08x..%08x\n",
224 | inh.IMPORT_DIRECTORY.VirtualAddress,
225 | inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size));
226 | DETOUR_TRACE(("obBaseAft = %08x..%08x\n", obBase, obBase + obStr));
227 |
228 | // If the file doesn't have an IAT_DIRECTORY, we create it...
229 | if (inh.IAT_DIRECTORY.VirtualAddress == 0) {
230 | inh.IAT_DIRECTORY.VirtualAddress = obBase;
231 | inh.IAT_DIRECTORY.Size = cbNew;
232 | }
233 |
234 | inh.IMPORT_DIRECTORY.VirtualAddress = obBase;
235 | inh.IMPORT_DIRECTORY.Size = cbNew;
236 |
237 | /////////////////////// Update the NT header for the new import directory.
238 | //
239 | if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
240 | PAGE_EXECUTE_READWRITE, &dwProtect)) {
241 | DETOUR_TRACE(("VirtualProtectEx(inh) write failed: %d\n", GetLastError()));
242 | goto finish;
243 | }
244 |
245 | inh.OptionalHeader.CheckSum = 0;
246 |
247 | if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
248 | DETOUR_TRACE(("WriteProcessMemory(idh) failed: %d\n", GetLastError()));
249 | goto finish;
250 | }
251 | DETOUR_TRACE(("WriteProcessMemory(idh:%p..%p)\n", pbModule, pbModule + sizeof(idh)));
252 |
253 | if (!WriteProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
254 | DETOUR_TRACE(("WriteProcessMemory(inh) failed: %d\n", GetLastError()));
255 | goto finish;
256 | }
257 | DETOUR_TRACE(("WriteProcessMemory(inh:%p..%p)\n",
258 | pbModule + idh.e_lfanew,
259 | pbModule + idh.e_lfanew + sizeof(inh)));
260 |
261 | if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
262 | dwProtect, &dwProtect)) {
263 | DETOUR_TRACE(("VirtualProtectEx(idh) restore failed: %d\n", GetLastError()));
264 | goto finish;
265 | }
266 |
267 | fSucceeded = TRUE;
268 | goto finish;
269 | }
270 |
--------------------------------------------------------------------------------
/deps/detours/system.mak:
--------------------------------------------------------------------------------
1 | ##############################################################################
2 | ##
3 | ## Establish build target type for Detours.
4 | ##
5 | ## Microsoft Research Detours Package, Version 3.0.
6 | ##
7 | ## Copyright (c) Microsoft Corporation. All rights reserved.
8 | ##
9 |
10 | ############################################## Determine Processor Build Type.
11 | ##
12 | !IF "$(DETOURS_TARGET_PROCESSOR)" == "" && "$(PROCESSOR_ARCHITEW6432)" != ""
13 | DETOURS_TARGET_PROCESSOR = X86
14 | !ENDIF
15 |
16 | !IF "$(DETOURS_TARGET_PROCESSOR)" == ""
17 | DETOURS_TARGET_PROCESSOR = $(PROCESSOR_ARCHITECTURE)
18 | !ENDIF
19 |
20 | # uppercase DETOURS_TARGET_PROCESSOR
21 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:a=A)
22 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:b=B)
23 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:c=C)
24 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:d=D)
25 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:e=E)
26 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:f=F)
27 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:g=G)
28 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:h=H)
29 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:i=I)
30 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:j=J)
31 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:k=K)
32 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:l=L)
33 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:m=M)
34 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:n=N)
35 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:o=O)
36 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:p=P)
37 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:q=Q)
38 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:r=R)
39 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:s=S)
40 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:t=T)
41 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:u=U)
42 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:v=V)
43 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:w=W)
44 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:x=X)
45 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:y=Y)
46 | DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:z=Z)
47 |
48 | !IF "$(DETOURS_TARGET_PROCESSOR)" == "AMD64"
49 | DETOURS_TARGET_PROCESSOR = X64
50 | !ENDIF
51 |
52 |
53 | !if "$(DETOURS_TARGET_PROCESSOR:64=)" == "$(DETOURS_TARGET_PROCESSOR)"
54 | DETOURS_32BIT=1
55 | DETOURS_BITS=32
56 | !else
57 | DETOURS_64BIT=1
58 | DETOURS_BITS=64
59 | !endif
60 |
61 | ########################################## Configure build based on Processor.
62 | ##
63 | ## DETOURS_OPTION_PROCESSOR: Set this macro if the processor *will* run code
64 | ## from another ISA (i.e. x86 on x64).
65 | ##
66 | ## DETOURS_OPTION_BITS: Set this macro if the processor *may* have an
67 | ## an alternative word size.
68 | ##
69 | !IF "$(DETOURS_TARGET_PROCESSOR)" == "X64"
70 | #!MESSAGE Building for 64-bit X64.
71 | DETOURS_SOURCE_BROWSING = 0
72 | DETOURS_OPTION_PROCESSOR=X86
73 | DETOURS_OPTION_BITS=32
74 | !ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "IA64"
75 | #!MESSAGE Building for 64-bit IA64.
76 | DETOURS_OPTION_PROCESSOR=X86
77 | DETOURS_OPTION_BITS=32
78 | !ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "X86"
79 | #!MESSAGE Building for 32-bit X86.
80 | DETOURS_OPTION_BITS=64
81 | # Don't set DETOURS_OPTION_PROCESSOR for x64 because we don't *know* that
82 | # we'll run on a 64-bit machine.
83 | !ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM"
84 | #!MESSAGE Building for 32-bit ARM.
85 | !ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64"
86 | #!MESSAGE Building for 64-bit ARM.
87 | !ELSE
88 | !MESSAGE Note: To select the target processor architecture set either
89 | !MESSAGE PROCESSOR_ARCHITECTURE or DETOURS_TARGET_PROCESSOR.
90 | !MESSAGE
91 | !ERROR Unknown target processor: $(DETOURS_TARGET_ARCHITECTURE)
92 | !ENDIF
93 |
94 | ##############################################################################
95 | ##
96 | INCD = $(ROOT)\include
97 | LIBD = $(ROOT)\lib.$(DETOURS_TARGET_PROCESSOR)$(DETOURS_CONFIG)
98 | BIND = $(ROOT)\bin.$(DETOURS_TARGET_PROCESSOR)$(DETOURS_CONFIG)
99 | OBJD = obj.$(DETOURS_TARGET_PROCESSOR)$(DETOURS_CONFIG)
100 | !IF "$(DETOURS_OPTION_PROCESSOR)" != ""
101 | OPTD = $(ROOT)\bin.$(DETOURS_OPTION_PROCESSOR)$(DETOURS_CONFIG)
102 | !ENDIF
103 |
104 | INCDS = $(ROOT)\include
105 |
106 | LIBDS = \
107 | $(ROOT)\lib.x86$(DETOURS_CONFIG) \
108 | $(ROOT)\lib.x64$(DETOURS_CONFIG) \
109 | $(ROOT)\lib.ia64$(DETOURS_CONFIG) \
110 | $(ROOT)\lib.arm$(DETOURS_CONFIG) \
111 | $(ROOT)\lib.arm64$(DETOURS_CONFIG) \
112 |
113 | BINDS = \
114 | $(ROOT)\bin.x86$(DETOURS_CONFIG) \
115 | $(ROOT)\bin.x64$(DETOURS_CONFIG) \
116 | $(ROOT)\bin.ia64$(DETOURS_CONFIG) \
117 | $(ROOT)\bin.arm$(DETOURS_CONFIG) \
118 | $(ROOT)\bin.arm64$(DETOURS_CONFIG) \
119 |
120 | OBJDS = \
121 | obj.x86$(DETOURS_CONFIG) \
122 | obj.x64$(DETOURS_CONFIG) \
123 | obj.ia64$(DETOURS_CONFIG) \
124 | obj.arm$(DETOURS_CONFIG) \
125 | obj.arm64$(DETOURS_CONFIG) \
126 |
127 | ##############################################################################
128 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_subdirectory("hook")
2 | add_subdirectory("inject")
--------------------------------------------------------------------------------
/src/experiments/agent.py:
--------------------------------------------------------------------------------
1 | """
2 | This scripe should be run in the guest VM with The Packer Attacker in it.
3 | It's a server application waiting for connections from unpack.py
4 | """
5 |
6 | import sys
7 | import os
8 | import subprocess
9 | import zipfile
10 |
11 | from bottle import route, run, SimpleTemplate, static_file, post, request
12 |
13 |
14 |
15 | # CONFIGURATION #################
16 | dumps_folder = 'C:\\dumps'
17 | archive_name = 'dumps.zip'
18 | port = 9000
19 | ################################
20 |
21 | def zipdir(path, zip):
22 | for root, dirs, files in os.walk(path):
23 | for file in files:
24 | zip.write(os.path.join(root, file))
25 |
26 | @route('/submit', method='POST')
27 | def submit():
28 |
29 | file = request.files.get('file')
30 |
31 | dst_path = '.'
32 |
33 | if not os.path.exists(file.filename):
34 | file.save(dst_path)
35 |
36 | subprocess.Popen(['PackerAttacker.exe', file.filename])
37 |
38 | return 'ok'
39 |
40 |
41 | @route('/retrieve', method='GET')
42 | def retrieve():
43 | zipf = zipfile.ZipFile(archive_name, 'w')
44 | zipdir(dumps_folder, zipf)
45 | zipf.close()
46 | return static_file(archive_name, root='.')
47 |
48 | def main():
49 |
50 | print "Starting server on port %d"%port
51 |
52 | run(host='', port=port)
53 |
54 |
55 | if __name__ == '__main__':
56 | main()
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/experiments/unpack.py:
--------------------------------------------------------------------------------
1 | """
2 | This script is supposed to be run from the host
3 | it will submit the file for unpacking to the VM armed
4 | with The Packer Attacker. It communicates to agent.py
5 | """
6 |
7 | import sys
8 | import os
9 | import subprocess
10 | import struct
11 | import requests
12 | import urllib
13 | import time
14 |
15 |
16 | # CONFIGURATION #################################
17 | # If you're using VirtualBox just put the name of the VM (not supported)
18 | vm_path = '/path/to/your/vm.vmx'
19 | # IP address and port of your VM (should be accessible from the host)
20 | vm_agent_url = 'http://:'
21 |
22 | submission_url = vm_agent_url+'/submit'
23 | retrieval_url = vm_agent_url+'/retrieve'
24 |
25 | # If you're using VirtualBox
26 | # vm_manager = 'VBoxManage'
27 | # You might need to include full path if running on Windows
28 | vm_manager = 'vmrun'
29 |
30 | # Name of snapshot to restore
31 | snapshot = 'snapshot name'
32 |
33 | # vm_type = 'vbox' not supported
34 | vm_type = 'vmware'
35 |
36 | # Time to unpack (in seconds)
37 | timeout = 20
38 | ###############################################
39 |
40 | IMAGE_FILE_DLL = 0x2000
41 |
42 |
43 |
44 | def main():
45 | if len(sys.argv)!=2:
46 | exit('Usage: %s '%sys.argv[0])
47 |
48 | exe = sys.argv[1]
49 |
50 | if not os.path.exists(exe):
51 | exit('%s does not exist'%exe)
52 |
53 | if os.path.isdir(exe):
54 | exit('%s is a directory'%exe)
55 |
56 | fd = open(exe, 'rb')
57 | data = fd.read()
58 | #fd.close()
59 |
60 | if data[:2]!='MZ':
61 | exit('%s: Invalide file - MZ header missing'%exe)
62 |
63 |
64 | pe_offset = struct.unpack('
5 | #include
6 |
7 | class DebugStackTracer : public StackWalker
8 | {
9 | public:
10 | DebugStackTracer() : StackWalker() {}
11 |
12 | DebugStackTracer(std::function callback) : StackWalker(StackWalker::RetrieveNone, NULL, GetCurrentProcessId(), GetCurrentProcess())
13 | {
14 | this->lineCallback = callback;
15 | }
16 |
17 | protected:
18 | virtual void OnOutput(LPCSTR szText)
19 | {
20 | lineCallback(std::string(szText));
21 | }
22 |
23 | private:
24 | std::function lineCallback;
25 | };
--------------------------------------------------------------------------------
/src/hook/HookingEngine.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | #include "detours.h"
7 |
8 | class HookingEngine
9 | {
10 | public:
11 | HookingEngine() : inTransaction(false) {}
12 | ~HookingEngine() {}
13 |
14 | void doTransaction(std::function transaction)
15 | {
16 | DetourTransactionBegin();
17 | DetourUpdateThread(GetCurrentThread());
18 | inTransaction = true;
19 | transaction();
20 | inTransaction = false;
21 | DetourTransactionCommit();
22 | }
23 |
24 | void placeHook(PVOID *hookAt, PVOID callback)
25 | {
26 | assert(inTransaction);
27 | DetourAttach(hookAt, callback);
28 | }
29 |
30 | void placeShallowExceptionHandlerHook(PVECTORED_EXCEPTION_HANDLER handler)
31 | {
32 | assert(inTransaction);
33 | AddVectoredExceptionHandler(1, handler);
34 | }
35 |
36 | void placeDeepExceptionHandlerHook(PVECTORED_EXCEPTION_HANDLER handler)
37 | {
38 | assert(inTransaction);
39 | AddVectoredExceptionHandler(0, handler);
40 | }
41 |
42 | bool injectIntoProcess(HANDLE process, const wchar_t* dllName)
43 | {
44 | LPVOID loadLibAddress = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW");
45 | LPVOID nameAddress = this->loadStringToMemory(process, dllName);
46 |
47 | if (!nameAddress || !loadLibAddress)
48 | return false;
49 |
50 | HANDLE creationThread = CreateRemoteThread(process, NULL, NULL, static_cast(loadLibAddress), nameAddress, NULL, NULL);
51 | if (creationThread)
52 | {
53 | WaitForSingleObject(creationThread, INFINITE);
54 |
55 | DWORD ret;
56 | GetExitCodeThread(creationThread, &ret);
57 | CloseHandle(creationThread);
58 |
59 | return (ret != NULL);
60 | }
61 | else
62 | return false;
63 | }
64 |
65 | private:
66 | bool inTransaction;
67 |
68 | LPVOID loadStringToMemory(HANDLE process, const wchar_t* str)
69 | {
70 | LPVOID argAddress = VirtualAllocEx(process, NULL, wcslen(str) * 2, MEM_COMMIT, PAGE_READWRITE);
71 | if (!argAddress)
72 | return 0;
73 | if (!WriteProcessMemory(process, argAddress, str, wcslen(str) * 2, NULL))
74 | return 0;
75 | return argAddress;
76 | }
77 |
78 | };
--------------------------------------------------------------------------------
/src/hook/Logger.cpp:
--------------------------------------------------------------------------------
1 | #include "Logger.h"
2 | #include "SyncLock.h"
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | Logger* Logger::instance= NULL;
9 |
10 | Logger::Logger(void)
11 | {
12 | this->lock = new SyncLock();
13 | }
14 | Logger::~Logger(void)
15 | {
16 | delete this->lock;
17 | }
18 | void Logger::initialize(std::string fileName)
19 | {
20 | this->logFile = new std::fstream(fileName, std::ios::out);
21 | }
22 | void Logger::uninitialize()
23 | {
24 | assert(this->logFile);
25 | this->logFile->close();
26 | delete this->logFile;
27 | }
28 |
29 | void Logger::write(const char* prefixFormat, const char* function, int lineNumber, std::string line)
30 | {
31 | assert(this->logFile);
32 | //assert(this->logFile->open());
33 |
34 | auto sg = this->lock->enterWithScopeGuard();
35 |
36 | this->writePrefix(prefixFormat, function, lineNumber);
37 | this->logFile->write(line.c_str(), line.length());
38 |
39 | if (line[line.length() - 1] != '\n')
40 | this->logFile->write("\n", 1);
41 |
42 | this->logFile->flush();
43 | }
44 | void Logger::write(const char* prefixFormat, const char* function, int lineNumber, const char* format, ...)
45 | {
46 | char buffer[4096];
47 | for (int i = 0; i < 4096; i++)
48 | buffer[i] = 0x00;
49 |
50 | va_list marker;
51 | va_start(marker, format);
52 | vsprintf_s(buffer, sizeof(buffer), format, marker);
53 | va_end(marker);
54 |
55 | this->write(prefixFormat, function, lineNumber, std::string(buffer));
56 | }
57 |
58 | void Logger::writePrefix(const char* prefixFormat, const char* function, int lineNumber)
59 | {
60 | time_t now = time(0);
61 | struct tm tstruct;
62 | char timebuffer[128], buffer[128];
63 |
64 | tstruct = *localtime(&now);
65 | strftime(timebuffer, sizeof(timebuffer), "[%Y-%m-%d.%X]", &tstruct);
66 |
67 | sprintf(buffer, prefixFormat, timebuffer, function, lineNumber);
68 | this->logFile->write(buffer, strlen(buffer));
69 | }
--------------------------------------------------------------------------------
/src/hook/Logger.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | #define _LOG_BASE_ __FUNCTION__, __LINE__
7 | #define LOG_ERROR "%s ERROR %s (%d) ", _LOG_BASE_
8 | #define LOG_INFO "%s INFO %s (%d) ", _LOG_BASE_
9 | #define LOG_WARN "%s WARN %s (%d) ", _LOG_BASE_
10 | #define LOG_APPENDLINE " ", _LOG_BASE_
11 |
12 | class SyncLock;
13 | class Logger
14 | {
15 | public:
16 | Logger(void);
17 | ~Logger(void);
18 |
19 | static Logger* getInstance()
20 | {
21 | if (Logger::instance == NULL)
22 | Logger::instance = new Logger();
23 | return Logger::instance;
24 | }
25 |
26 | void initialize(std::string fileName);
27 | void uninitialize();
28 |
29 | void write(const char* prefixFormat, const char* function, int lineNumber, std::string line);
30 | void write(const char* prefixFormat, const char* function, int lineNumber, const char* format, ...);
31 |
32 | private:
33 | static Logger* instance;
34 | std::fstream* logFile;
35 | SyncLock* lock;
36 |
37 | void writePrefix(const char* prefixFormat, const char* function, int lineNumber);
38 | };
39 |
40 |
--------------------------------------------------------------------------------
/src/hook/Memory.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | template static T AdjustPointerRVA(DWORD rva, IMAGE_NT_HEADERS* ntHeader, BYTE* imageBase)
5 | {
6 | auto pSectionHdr = GetEnclosingSectionHeader(rva, ntHeader);
7 | if (!pSectionHdr)
8 | return 0;
9 | int delta = (int)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
10 | return (T)((void*)(imageBase + rva - delta));
11 | }
12 | template static T MakePointer(Tp pointer, DWORD_PTR addition)
13 | {
14 | return (T)((DWORD_PTR)pointer + (DWORD_PTR)addition);
15 | }
16 |
17 | template static T GetDelta(Ta a, Tb b)
18 | {
19 | return (T)((DWORD_PTR)a - (DWORD_PTR)b);
20 | }
--------------------------------------------------------------------------------
/src/hook/SharedMemoryArray.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | // ditching this for now
6 | #ifdef 0
7 |
8 | template
9 | struct SharedMemoryDefinition
10 | {
11 | unsigned int elementCount;
12 | T elements[SIZE];
13 | };
14 |
15 | template
16 | class SharedMemoryArray
17 | {
18 | public:
19 |
20 | SharedMemoryArray(std::string _name) : name(_name), sharedMemoryHande(INVALID_HANDLE_VALUE), SharedMemoryDefinition(NULL) {}
21 | ~SharedMemoryArray(void)
22 | {
23 | }
24 |
25 | bool initialize()
26 | {
27 | /* don't need to try if we already have a handle */
28 | if (this->sharedMemoryHande != INVALID_HANDLE_VALUE)
29 | return true;
30 |
31 | this->sharedMemoryHande = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(SharedMemoryDefinition), this->name.c_str());
32 |
33 | /* make sure it succeeded */
34 | if (this->sharedMemoryHande == INVALID_HANDLE_VALUE)
35 | return false;
36 |
37 | /* get a pointer to it and zero it out if we're the first holder */
38 | bool Created = (GetLastError() != ERROR_ALREADY_EXISTS);
39 | this->sharedMemorySegment = (SharedMemoryDefinition*)MapViewOfFile(this->sharedMemorySegment, FILE_MAP_WRITE, 0, 0, 0);
40 | if (Created)
41 | ZeroMemory(this->sharedMemorySegment, sizeof(SharedMemoryDefinition));
42 |
43 | return true;
44 | }
45 |
46 | bool addElement(T value)
47 | {
48 | if (this->sharedMemorySegment->elementCount == SIZE)
49 | return false;
50 |
51 | this->sharedMemorySegment->elements[this->sharedMemorySegment->elementCount] = value;
52 | this->sharedMemorySegment->elementCount++;
53 |
54 | return true;
55 | }
56 |
57 | T getElement(unsigned int index)
58 | {
59 | return this->sharedMemorySegment->elements[index];
60 | }
61 |
62 | private:
63 |
64 |
65 | std::string name;
66 | HANDLE sharedMemoryHande;
67 | SharedMemoryDefinition* sharedMemorySegment;
68 | };
69 |
70 | #endif
--------------------------------------------------------------------------------
/src/hook/StackWalker.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BromiumLabs/PackerAttacker/24294220bf1d74146a9bf7a37c9de19230c182d5/src/hook/StackWalker.cpp
--------------------------------------------------------------------------------
/src/hook/StackWalker.h:
--------------------------------------------------------------------------------
1 | /* this is an open source class from Code Project. It was not made by or for the creators of The Packer Attacker*/
2 | /**********************************************************************
3 | *
4 | * StackWalker.h
5 | *
6 | *
7 | * History:
8 | * 2005-07-27 v1 - First public release on http://www.codeproject.com/
9 | * (for additional changes see History in 'StackWalker.cpp'!
10 | *
11 | **********************************************************************/
12 | // #pragma once is supported starting with _MCS_VER 1000,
13 | // so we need not to check the version (because we only support _MSC_VER >= 1100)!
14 | #pragma once
15 |
16 | #include
17 |
18 | // special defines for VC5/6 (if no actual PSDK is installed):
19 | #if _MSC_VER < 1300
20 | typedef unsigned __int64 DWORD64, *PDWORD64;
21 | #if defined(_WIN64)
22 | typedef unsigned __int64 SIZE_T, *PSIZE_T;
23 | #else
24 | typedef unsigned long SIZE_T, *PSIZE_T;
25 | #endif
26 | #endif // _MSC_VER < 1300
27 |
28 | class StackWalkerInternal; // forward
29 | class StackWalker
30 | {
31 | public:
32 | typedef enum StackWalkOptions
33 | {
34 | // No addition info will be retrived
35 | // (only the address is available)
36 | RetrieveNone = 0,
37 |
38 | // Try to get the symbol-name
39 | RetrieveSymbol = 1,
40 |
41 | // Try to get the line for this symbol
42 | RetrieveLine = 2,
43 |
44 | // Try to retrieve the module-infos
45 | RetrieveModuleInfo = 4,
46 |
47 | // Also retrieve the version for the DLL/EXE
48 | RetrieveFileVersion = 8,
49 |
50 | // Contains all the abouve
51 | RetrieveVerbose = 0xF,
52 |
53 | // Generate a "good" symbol-search-path
54 | SymBuildPath = 0x10,
55 |
56 | // Also use the public Microsoft-Symbol-Server
57 | SymUseSymSrv = 0x20,
58 |
59 | // Contains all the abouve "Sym"-options
60 | SymAll = 0x30,
61 |
62 | // Contains all options (default)
63 | OptionsAll = 0x3F
64 | } StackWalkOptions;
65 |
66 | StackWalker(
67 | int options = OptionsAll, // 'int' is by design, to combine the enum-flags
68 | LPCSTR szSymPath = NULL,
69 | DWORD dwProcessId = GetCurrentProcessId(),
70 | HANDLE hProcess = GetCurrentProcess()
71 | );
72 | StackWalker(DWORD dwProcessId, HANDLE hProcess);
73 | virtual ~StackWalker();
74 |
75 | typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
76 | HANDLE hProcess,
77 | DWORD64 qwBaseAddress,
78 | PVOID lpBuffer,
79 | DWORD nSize,
80 | LPDWORD lpNumberOfBytesRead,
81 | LPVOID pUserData // optional data, which was passed in "ShowCallstack"
82 | );
83 |
84 | BOOL LoadModules();
85 |
86 | BOOL ShowCallstack(
87 | HANDLE hThread = GetCurrentThread(),
88 | const CONTEXT *context = NULL,
89 | PReadProcessMemoryRoutine readMemoryFunction = NULL,
90 | LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
91 | );
92 |
93 | #if _MSC_VER >= 1300
94 | // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
95 | // in older compilers in order to use it... starting with VC7 we can declare it as "protected"
96 | protected:
97 | #endif
98 | enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
99 |
100 | protected:
101 | // Entry for each Callstack-Entry
102 | typedef struct CallstackEntry
103 | {
104 | DWORD64 offset; // if 0, we have no valid entry
105 | CHAR name[STACKWALK_MAX_NAMELEN];
106 | CHAR undName[STACKWALK_MAX_NAMELEN];
107 | CHAR undFullName[STACKWALK_MAX_NAMELEN];
108 | DWORD64 offsetFromSmybol;
109 | DWORD offsetFromLine;
110 | DWORD lineNumber;
111 | CHAR lineFileName[STACKWALK_MAX_NAMELEN];
112 | DWORD symType;
113 | LPCSTR symTypeString;
114 | CHAR moduleName[STACKWALK_MAX_NAMELEN];
115 | DWORD64 baseOfImage;
116 | CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
117 | } CallstackEntry;
118 |
119 | typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
120 |
121 | virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
122 | virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
123 | virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
124 | virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
125 | virtual void OnOutput(LPCSTR szText);
126 |
127 | StackWalkerInternal *m_sw;
128 | HANDLE m_hProcess;
129 | DWORD m_dwProcessId;
130 | BOOL m_modulesLoaded;
131 | LPSTR m_szSymPath;
132 |
133 | int m_options;
134 |
135 | static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
136 |
137 | friend StackWalkerInternal;
138 | };
139 |
140 |
141 | // The "ugly" assembler-implementation is needed for systems before XP
142 | // If you have a new PSDK and you only compile for XP and later, then you can use
143 | // the "RtlCaptureContext"
144 | // Currently there is no define which determines the PSDK-Version...
145 | // So we just use the compiler-version (and assumes that the PSDK is
146 | // the one which was installed by the VS-IDE)
147 |
148 | // INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
149 | // But I currently use it in x64/IA64 environments...
150 | //#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
151 |
152 | #if defined(_M_IX86)
153 | #ifdef CURRENT_THREAD_VIA_EXCEPTION
154 | // TODO: The following is not a "good" implementation,
155 | // because the callstack is only valid in the "__except" block...
156 | #define GET_CURRENT_CONTEXT(c, contextFlags) \
157 | do { \
158 | memset(&c, 0, sizeof(CONTEXT)); \
159 | EXCEPTION_POINTERS *pExp = NULL; \
160 | __try { \
161 | throw 0; \
162 | } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
163 | if (pExp != NULL) \
164 | memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
165 | c.ContextFlags = contextFlags; \
166 | } while(0);
167 | #else
168 | // The following should be enough for walking the callstack...
169 | #define GET_CURRENT_CONTEXT(c, contextFlags) \
170 | do { \
171 | memset(&c, 0, sizeof(CONTEXT)); \
172 | c.ContextFlags = contextFlags; \
173 | __asm call x \
174 | __asm x: pop eax \
175 | __asm mov c.Eip, eax \
176 | __asm mov c.Ebp, ebp \
177 | __asm mov c.Esp, esp \
178 | } while(0);
179 | #endif
180 |
181 | #else
182 |
183 | // The following is defined for x86 (XP and higher), x64 and IA64:
184 | #define GET_CURRENT_CONTEXT(c, contextFlags) \
185 | do { \
186 | memset(&c, 0, sizeof(CONTEXT)); \
187 | c.ContextFlags = contextFlags; \
188 | RtlCaptureContext(&c); \
189 | } while(0);
190 | #endif
191 |
--------------------------------------------------------------------------------
/src/hook/SyncLock.cpp:
--------------------------------------------------------------------------------
1 | #include "SyncLock.h"
2 |
3 | SyncLockScopeGuard::SyncLockScopeGuard(SyncLock* _lock) : lock(_lock)
4 | {
5 | this->lock->enter();
6 | }
7 | SyncLockScopeGuard::~SyncLockScopeGuard(void)
8 | {
9 | this->lock->leave();
10 | }
11 |
12 | SyncLock::SyncLock(void)
13 | {
14 | InitializeCriticalSection(&this->lock);
15 | }
16 | SyncLock::~SyncLock(void)
17 | {
18 | DeleteCriticalSection(&this->lock);
19 | }
20 |
21 | void SyncLock::enter()
22 | {
23 | EnterCriticalSection(&this->lock);
24 | }
25 |
26 | void SyncLock::leave()
27 | {
28 | LeaveCriticalSection(&this->lock);
29 | }
30 |
--------------------------------------------------------------------------------
/src/hook/SyncLock.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | class SyncLock;
6 | class SyncLockScopeGuard
7 | {
8 | public:
9 | SyncLockScopeGuard(SyncLock* _lock);
10 | ~SyncLockScopeGuard(void);
11 |
12 | private:
13 | SyncLock* lock;
14 | };
15 |
16 |
17 | class SyncLock
18 | {
19 | public:
20 | SyncLock(void);
21 | ~SyncLock(void);
22 |
23 | void enter();
24 | void leave();
25 |
26 | inline std::shared_ptr SyncLock::enterWithScopeGuard()
27 | {
28 | return std::shared_ptr(new SyncLockScopeGuard(this));
29 | }
30 |
31 | private:
32 | CRITICAL_SECTION lock;
33 | };
34 |
--------------------------------------------------------------------------------
/src/hook/TrackedMemoryBlock.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | struct TrackedMemoryBlock
7 | {
8 | DWORD startAddress, endAddress, size;
9 | DWORD neededProtection;
10 |
11 | TrackedMemoryBlock(DWORD _startAddress, DWORD _size, DWORD _neededProtection = NULL)
12 | {
13 | this->startAddress = _startAddress;
14 | this->endAddress = _startAddress + _size;
15 | this->size = _size;
16 | this->neededProtection = _neededProtection;
17 | }
18 |
19 | bool overlapsWith(TrackedMemoryBlock right, bool oneSided = false)
20 | {
21 | if (!oneSided)
22 | if (right.overlapsWith(*this, true))
23 | return true;
24 | return (right.startAddress >= this->startAddress && right.startAddress <= this->endAddress);
25 | }
26 |
27 | virtual void mergeWith(TrackedMemoryBlock right)
28 | {
29 | DWORD protectionTemp = right.neededProtection;
30 | if (this->overlapsWith(right, true))
31 | {
32 | this->endAddress = right.endAddress;
33 | this->size = this->endAddress - this->startAddress;
34 | }
35 | else if (right.overlapsWith(*this, true))
36 | {
37 | TrackedMemoryBlock temp(right);
38 | temp.mergeWith(*this);
39 |
40 | this->startAddress = temp.startAddress;
41 | this->endAddress = temp.endAddress;
42 | this->size = temp.size;
43 | }
44 | else
45 | return;
46 |
47 | this->neededProtection = protectionTemp;
48 | }
49 | };
50 |
51 |
52 | struct TrackedCopiedMemoryBlock : public TrackedMemoryBlock
53 | {
54 | std::vector buffer;
55 | TrackedCopiedMemoryBlock(DWORD _startAddress, DWORD _size, unsigned char* _buffer)
56 | : TrackedMemoryBlock(_startAddress, _size, PAGE_NOACCESS)
57 | {
58 | this->buffer.reserve(size);
59 | for (unsigned int i = 0; i < size; i++)
60 | this->buffer.push_back(_buffer[i]);
61 | }
62 |
63 | virtual void mergeWith(TrackedCopiedMemoryBlock right)
64 | {
65 | DWORD protectionTemp = right.neededProtection;
66 | if (this->overlapsWith(right, true))
67 | {
68 | /* we need to copy on top of existing bytes */
69 | unsigned int startIndex = right.startAddress - this->startAddress;
70 | unsigned int oI = startIndex; //overwrite index
71 | unsigned int cI = 0; //copy index
72 |
73 | /* copy over existing data */
74 | for (; oI < this->size; oI++, cI++)
75 | this->buffer[oI] = right.buffer[cI];
76 |
77 | /* copy over trailing data */
78 | for (; cI < right.size; cI++, oI++)
79 | {
80 | assert(oI <= this->buffer.size());
81 | if (oI == this->buffer.size())
82 | this->buffer.push_back(right.buffer[cI]);
83 | else
84 | this->buffer[oI] = right.buffer[cI];
85 | }
86 |
87 | this->endAddress = right.endAddress;
88 | this->size = this->endAddress - this->startAddress;
89 | }
90 | else if (right.overlapsWith(*this, true))
91 | {
92 | TrackedCopiedMemoryBlock temp(right);
93 | temp.mergeWith(*this);
94 |
95 | this->startAddress = temp.startAddress;
96 | this->endAddress = temp.endAddress;
97 | this->size = temp.size;
98 | this->buffer = temp.buffer;
99 | }
100 | else
101 | return;
102 |
103 | this->neededProtection = protectionTemp;
104 | }
105 | };
106 |
107 | template
108 | struct MemoryBlockTracker
109 | {
110 | std::list trackedMemoryBlocks;
111 |
112 | typename std::list::iterator nullMarker()
113 | {
114 | return this->trackedMemoryBlocks.end();
115 | }
116 | typename std::list::iterator findTracked(DWORD address, DWORD size)
117 | {
118 | return findTracked(TrackType(address, size));
119 | }
120 | typename std::list::iterator findTracked(TrackType check)
121 | {
122 | for (auto it = this->trackedMemoryBlocks.begin(); it != this->trackedMemoryBlocks.end(); it++)
123 | if (it->overlapsWith(check))
124 | return it;
125 |
126 | return this->trackedMemoryBlocks.end();
127 | }
128 | bool isTracked(DWORD address, DWORD size)
129 | {
130 | return isTracked(TrackType(address, size));
131 | }
132 | bool isTracked(TrackedMemoryBlock check)
133 | {
134 | return findTracked(check) != this->nullMarker();
135 | }
136 | void startTracking(DWORD address, DWORD size, DWORD protection)
137 | {
138 | startTracking(TrackType(address, size, protection));
139 | }
140 | void startTracking(TrackType right)
141 | {
142 | auto it = this->findTracked(right);
143 | if (it != this->nullMarker())
144 | it->mergeWith(right);
145 | else
146 | this->trackedMemoryBlocks.push_back(right);
147 | }
148 | void stopTracking(DWORD address, DWORD size)
149 | {
150 | this->stopTracking(this->findTracked(address, size));
151 | }
152 | void stopTracking(typename std::list::iterator it)
153 | {
154 | assert(it != this->trackedMemoryBlocks.end());
155 |
156 | this->trackedMemoryBlocks.erase(it);
157 | }
158 | };
--------------------------------------------------------------------------------
/src/hook/UnpackingEngine.cpp:
--------------------------------------------------------------------------------
1 | #include "UnpackingEngine.h"
2 | #include "Memory.h"
3 | #include "Logger.h"
4 | #include "DebugStackTracer.h"
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | UnpackingEngine* UnpackingEngine::instance = NULL;
12 |
13 | UnpackingEngine::UnpackingEngine(void)
14 | {
15 | this->hooks = new HookingEngine();
16 | this->lock = new SyncLock();
17 | this->hooksReady = false;
18 | this->inAllocationHook = false;
19 | this->bypassHooks = false;
20 | }
21 |
22 |
23 | UnpackingEngine::~UnpackingEngine(void)
24 | {
25 | delete this->hooks;
26 | delete this->lock;
27 | }
28 |
29 | void UnpackingEngine::initialize()
30 | {
31 | auto sg = this->lock->enterWithScopeGuard();
32 |
33 | this->processID = GetCurrentProcessId();
34 |
35 | /* init logger */
36 | char logName[MAX_PATH];
37 | sprintf_s(logName, "C:\\dumps\\[%d]_packer_attacker.log", this->processID);
38 | Logger::getInstance()->initialize(logName);
39 |
40 | Logger::getInstance()->write(LOG_INFO, "Starting hooking process...");
41 |
42 | /* get the current DEP state, then make sure DEP is on */
43 | DWORD depFlags;
44 | BOOL depCantChange;
45 | GetProcessDEPPolicy(GetCurrentProcess(), &depFlags, &depCantChange);
46 | this->simulateDisabledDEP = (depFlags & PROCESS_DEP_ENABLE) != PROCESS_DEP_ENABLE;
47 |
48 | if (this->simulateDisabledDEP && depCantChange)
49 | Logger::getInstance()->write(LOG_ERROR, "Cannot enable DEP for this process!");
50 | else
51 | SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
52 |
53 | /* place hooks and track PE section */
54 | HOOK_GET_ORIG(this, "ntdll.dll", NtProtectVirtualMemory);
55 | HOOK_GET_ORIG(this, "ntdll.dll", NtWriteVirtualMemory);
56 | HOOK_GET_ORIG(this, "ntdll.dll", NtCreateThread);
57 | HOOK_GET_ORIG(this, "ntdll.dll", NtMapViewOfSection);
58 | HOOK_GET_ORIG(this, "ntdll.dll", NtResumeThread);
59 | HOOK_GET_ORIG(this, "ntdll.dll", NtDelayExecution);
60 | HOOK_GET_ORIG(this, "ntdll.dll", NtAllocateVirtualMemory);
61 | HOOK_GET_ORIG(this, "ntdll.dll", RtlDecompressBuffer);
62 | HOOK_GET_ORIG(this, "Kernel32.dll", CreateProcessInternalW);
63 |
64 |
65 | Logger::getInstance()->write(LOG_INFO, "Finding original function addresses... DONE");
66 |
67 | this->startTrackingPEMemoryBlocks();
68 |
69 | Logger::getInstance()->write(LOG_INFO, "Tracking PE memory blocks... DONE");
70 |
71 | this->hooks->doTransaction([=](){
72 | this->hooks->placeShallowExceptionHandlerHook(&UnpackingEngine::_onShallowException);
73 | this->hooks->placeDeepExceptionHandlerHook(&UnpackingEngine::_onDeepException);
74 | HOOK_SET(this, this->hooks, NtProtectVirtualMemory);
75 | HOOK_SET(this, this->hooks, NtWriteVirtualMemory);
76 | HOOK_SET(this, this->hooks, NtCreateThread);
77 | HOOK_SET(this, this->hooks, NtMapViewOfSection);
78 | HOOK_SET(this, this->hooks, NtResumeThread);
79 | HOOK_SET(this, this->hooks, NtDelayExecution);
80 | HOOK_SET(this, this->hooks, NtAllocateVirtualMemory);
81 | HOOK_SET(this, this->hooks, RtlDecompressBuffer);
82 | HOOK_SET(this, this->hooks, CreateProcessInternalW);
83 | });
84 |
85 | Logger::getInstance()->write(LOG_INFO, "Placing hooks... DONE");
86 | Logger::getInstance()->write(LOG_INFO, "Hooks ready!");
87 |
88 | hooksReady = true;
89 | }
90 |
91 | void UnpackingEngine::uninitialize()
92 | {
93 | auto sg = this->lock->enterWithScopeGuard();
94 |
95 | this->dumpRemoteMemoryBlocks();
96 | Logger::getInstance()->uninitialize();
97 | }
98 |
99 | void UnpackingEngine::startTrackingPEMemoryBlocks()
100 | {
101 | auto mainModule = (BYTE*)GetModuleHandle(NULL);
102 | assert(mainModule);
103 |
104 | auto dosHeader = MakePointer(mainModule, 0);
105 | if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
106 | return;
107 |
108 | auto ntHeaders = MakePointer(mainModule, dosHeader->e_lfanew);
109 | if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
110 | return;
111 |
112 | auto baseOfCode = MakePointer((HMODULE)mainModule, ntHeaders->OptionalHeader.BaseOfCode);
113 | auto baseOfData = MakePointer((HMODULE)mainModule, ntHeaders->OptionalHeader.BaseOfData);
114 | auto entryPoint = MakePointer((HMODULE)mainModule, ntHeaders->OptionalHeader.AddressOfEntryPoint);
115 |
116 | Logger::getInstance()->write(LOG_INFO, "PE HEADER SAYS\n\tCode: 0x%0x\n\tData: 0x%0x\n\tEP: 0x%0x", baseOfCode, baseOfData, entryPoint);
117 |
118 |
119 | bool eipAlreadyIgnored = false;
120 | auto sectionHeader = IMAGE_FIRST_SECTION(ntHeaders);
121 | for (DWORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++, sectionHeader++)
122 | {
123 | DWORD destination = MakePointer((HMODULE)mainModule, sectionHeader->VirtualAddress);
124 | DWORD size = sectionHeader->SizeOfRawData;
125 | if (size <= 0)
126 | {
127 | auto nextSection = sectionHeader; nextSection++;
128 | size = nextSection->VirtualAddress - sectionHeader->VirtualAddress;
129 | }
130 |
131 | PESections.push_back(std::make_pair(destination, destination + size));
132 |
133 | if (!CHECK_FLAG(sectionHeader->Characteristics, CHARACTERISTIC_WRITEABLE))
134 | continue; /* skip un-writeable sections */
135 |
136 | if (!CHECK_FLAG(sectionHeader->Characteristics, CHARACTERISTIC_EXECUTABLE))
137 | continue; /* skip non-executable sections */
138 |
139 |
140 | ULONG oldProtection;
141 | auto ret = this->origNtProtectVirtualMemory(GetCurrentProcess(), (PVOID*)&destination, (PULONG)&size, PAGE_EXECUTE_READ, &oldProtection);
142 | if (ret != 0)
143 | {
144 | Logger::getInstance()->write(LOG_ERROR, "Failed to remove execution rights from %s at 0x%08x (char: 0x%08x). GetLastError() == %d | RET == 0x%08x", sectionHeader->Name, destination, sectionHeader->Characteristics, GetLastError(), ret);
145 | continue; /* failed to remove write privs ;( */
146 | }
147 |
148 | this->writeablePEBlocks.startTracking(destination, size, oldProtection);
149 |
150 | Logger::getInstance()->write(LOG_INFO, "Placed hook on PE section %s at 0x%08x to 0x%08x (char: 0x%08x)", sectionHeader->Name, destination, destination+size, sectionHeader->Characteristics);
151 | }
152 |
153 | }
154 |
155 | bool UnpackingEngine::isPEMemory(DWORD address)
156 | {
157 | for (unsigned int i = 0; i < this->PESections.size(); i++)
158 | if (address >= this->PESections[i].first && address <= this->PESections[i].second)
159 | return true;
160 | return false;
161 | }
162 |
163 | void UnpackingEngine::startTrackingRemoteMemoryBlock(DWORD pid, DWORD baseAddress, DWORD size, unsigned char* data)
164 | {
165 | if (this->remoteMemoryBlocks.find(pid) == this->remoteMemoryBlocks.end())
166 | this->remoteMemoryBlocks[pid] = MemoryBlockTracker();
167 |
168 | TrackedCopiedMemoryBlock add(baseAddress, size, data);
169 | this->remoteMemoryBlocks[pid].startTracking(add);
170 | }
171 |
172 | void UnpackingEngine::dumpRemoteMemoryBlocks()
173 | {
174 | for (auto mIT = this->remoteMemoryBlocks.begin(); mIT != this->remoteMemoryBlocks.end(); mIT++)
175 | {
176 | auto PID = mIT->first;
177 | auto blocks = mIT->second;
178 | for (auto IT = blocks.trackedMemoryBlocks.begin(); IT != blocks.trackedMemoryBlocks.end(); IT++)
179 | {
180 | if (IT->size < 50)
181 | continue;
182 |
183 | char fileName[MAX_PATH];
184 | sprintf(fileName, "C:\\dumps\\[%d]_%d_0x%08x_to_0x%08x.WPM.DMP", PID, GetTickCount(), IT->startAddress, IT->endAddress);
185 | this->dumpMemoryBlock(fileName, IT->buffer.size(), (const unsigned char*)IT->buffer.data());
186 | }
187 | }
188 | }
189 |
190 | void UnpackingEngine::dumpMemoryBlock(TrackedMemoryBlock block, DWORD ep)
191 | {
192 | char fileName[MAX_PATH];
193 | sprintf(fileName, "C:\\dumps\\[%d]_%d_0x%p_to_0x%p_EP_0x%p_IDX_%d.DMP", this->processID, GetTickCount(), block.startAddress, block.endAddress, ep, ep - block.startAddress);
194 |
195 | this->dumpMemoryBlock(fileName, block.size, (const unsigned char*)block.startAddress);
196 | }
197 |
198 | void UnpackingEngine::dumpMemoryBlock(char* fileName, DWORD size, const unsigned char* data)
199 | {
200 | std::fstream file(fileName, std::ios::out | std::ios::binary);
201 | if (file.is_open())
202 | {
203 | for (int i = 0; i < size; i++)
204 | file.write((const char*)&data[i], 1);
205 | file.close();
206 | }
207 | else
208 | Logger::getInstance()->write(LOG_ERROR, "Failed to create dump file with name '%s'!", fileName);
209 | }
210 |
211 | bool UnpackingEngine::isSelfProcess(HANDLE process)
212 | {
213 | return (process == 0 || process == INVALID_HANDLE_VALUE || GetProcessId(process) == this->processID);
214 | }
215 |
216 | DWORD UnpackingEngine::getProcessIdIfRemote(HANDLE process)
217 | {
218 | if (process == 0 && process == INVALID_HANDLE_VALUE)
219 | return 0;
220 |
221 | DWORD pid = GetProcessId(process);
222 | return (pid == this->processID) ? 0 : pid;
223 | }
224 |
225 | ULONG UnpackingEngine::processMemoryBlockFromHook(const char* source, DWORD address, DWORD size, ULONG newProtection, ULONG oldProtection, bool considerOldProtection)
226 | {
227 | PVOID _address = (PVOID)address;
228 | DWORD _size = size;
229 | ULONG _oldProtection = oldProtection;
230 |
231 | auto it = this->writeablePEBlocks.findTracked(address, size);
232 | if (it != this->writeablePEBlocks.nullMarker())
233 | {
234 | /* this is a PE section that we're currently tracking, let's make sure it stays that way */
235 | if (IS_WRITEABLE_PROT(newProtection))
236 | {
237 | this->origNtProtectVirtualMemory(GetCurrentProcess(), &_address, &_size, REMOVE_WRITEABLE_PROT(newProtection), &_oldProtection);
238 | Logger::getInstance()->write(LOG_INFO, "[%s] Persisting hook on PE section at 0x%08x - 0x%08x", source, address, address + size);
239 | }
240 | else
241 | Logger::getInstance()->write(LOG_INFO, "[%s] Block detected as writeable PE block, no need to persist hook 0x%08x - 0x%08x", source, address, address + size);
242 | }
243 | else if (considerOldProtection &&
244 | IS_WRITEABLE_PROT(newProtection) &&
245 | !IS_WRITEABLE_PROT(oldProtection) &&
246 | this->isPEMemory(address)) // newly writeable pe section
247 | {
248 | /* this is a PE section being set to writeable, track it */
249 | this->origNtProtectVirtualMemory(GetCurrentProcess(), &_address, &_size, REMOVE_WRITEABLE_PROT(newProtection), &_oldProtection);
250 | this->writeablePEBlocks.startTracking(address, size, newProtection);
251 | Logger::getInstance()->write(LOG_INFO, "[%s] Placed write hook on PE section at 0x%08x - 0x%08x", source, address, address + size);
252 | }
253 | else if (IS_EXECUTABLE_PROT(newProtection))
254 | {
255 | /* page was set to executable, track the page and remove executable rights */
256 | if (!this->blacklistedBlocks.isTracked(address, size))
257 | {
258 | this->executableBlocks.startTracking(address, size, (DWORD)newProtection);
259 | this->origNtProtectVirtualMemory(GetCurrentProcess(), &_address, &_size, REMOVE_EXECUTABLE_PROT(newProtection), &_oldProtection);
260 | Logger::getInstance()->write(LOG_INFO, "[%s] Placed execution hook on 0x%08x - 0x%08x", source, address, address + size);
261 | }
262 | else
263 | Logger::getInstance()->write(LOG_WARN, "[%s] Failed to place execution hook on BLACKLISTED BLOCK 0x%08x - 0x%08x", source, address, address + size);
264 | }
265 | else
266 | {
267 | auto it = this->executableBlocks.findTracked(address, size);
268 | if (it == this->executableBlocks.nullMarker())
269 | Logger::getInstance()->write(LOG_INFO, "[%s] No need to hook block 0x%08x - 0x%08x", source, address, address + size);
270 | }
271 |
272 | return _oldProtection;
273 | }
274 |
275 | NTSTATUS UnpackingEngine::onNtProtectVirtualMemory(HANDLE process, PVOID* baseAddress, PULONG numberOfBytes, ULONG newProtection, PULONG OldProtection)
276 | {
277 | /* do original protection */
278 | ULONG _oldProtection;
279 | auto ret = this->origNtProtectVirtualMemory(process, baseAddress, numberOfBytes, newProtection, &_oldProtection);
280 |
281 | if (OldProtection)
282 | *OldProtection = _oldProtection;
283 |
284 | /* we do not want to re-process this if we did in NtAllocate hook, as it sometimes calls NtProtect */
285 | if (this->inAllocationHook)
286 | return ret;
287 |
288 | if (ret == 0 && this->hooksReady)
289 | Logger::getInstance()->write(LOG_INFO, "NtProtectVirtualMemory(TargetPID %d, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", GetProcessId(process), (DWORD)*baseAddress, (DWORD)*numberOfBytes, newProtection, OldProtection);
290 |
291 | if (ret == 0 && this->hooksReady && this->isSelfProcess(process))
292 | {
293 | _oldProtection = this->processMemoryBlockFromHook("onNtProtectVirtualMemory", (DWORD)*baseAddress, (DWORD)*numberOfBytes, newProtection, *OldProtection, true);
294 | if (OldProtection)
295 | *OldProtection = _oldProtection;
296 | }
297 |
298 | return ret;
299 | }
300 |
301 | NTSTATUS UnpackingEngine::onNtWriteVirtualMemory(HANDLE process, PVOID baseAddress, PVOID buffer, ULONG numberOfBytes, PULONG numberOfBytesWritten)
302 | {
303 | if (this->hooksReady)
304 | Logger::getInstance()->write(LOG_INFO, "PRE-NtWriteVirtualMemory(TargetPID %d, Address 0x%08x, Count 0x%08x)\n", GetProcessId(process), baseAddress, numberOfBytes);
305 |
306 | auto ret = this->origNtWriteVirtualMemory(process, baseAddress, buffer, numberOfBytes, numberOfBytesWritten);
307 |
308 | if (this->hooksReady)
309 | Logger::getInstance()->write(LOG_INFO, "PST-NtWriteVirtualMemory(TargetPID %d, Address 0x%08x, Count 0x%08x) RET: 0x%08x\n", GetProcessId(process), baseAddress, (numberOfBytesWritten) ? *numberOfBytesWritten : numberOfBytes, ret);
310 |
311 | if (ret == 0 && this->hooksReady)
312 | {
313 | DWORD targetPID = this->getProcessIdIfRemote(process);
314 | if (targetPID)
315 | this->startTrackingRemoteMemoryBlock(targetPID, (DWORD)baseAddress, (DWORD)numberOfBytes, (unsigned char*)buffer);
316 | }
317 |
318 | return ret;
319 | }
320 |
321 | BOOL WINAPI UnpackingEngine::onCreateProcessInternalW(
322 | HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
323 | LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes,
324 | BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
325 | LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation, PHANDLE hNewToken)
326 | {
327 | auto ret = origCreateProcessInternalW(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes,
328 | bInheritHandles, dwCreationFlags | CREATE_SUSPENDED, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken);
329 |
330 | if ((dwCreationFlags & CREATE_SUSPENDED) != CREATE_SUSPENDED)
331 | {
332 | /* the process wasnt initially suspended, so we can inject right away */
333 | Logger::getInstance()->write(LOG_INFO, "Propogating into process %d from CreateProcessInternalW() hook.\n", lpProcessInformation->dwProcessId);
334 | hooks->injectIntoProcess(lpProcessInformation->hProcess, L"PackerAttackerHook.dll");
335 | Logger::getInstance()->write(LOG_INFO, "Propogation into process %d from CreateProcessInternalW() hook COMPLETE!\n", lpProcessInformation->dwProcessId);
336 |
337 | if (ResumeThread(lpProcessInformation->hThread) == -1)
338 | Logger::getInstance()->write(LOG_ERROR, "Failed to resume process! Thread %d\n", lpProcessInformation->dwThreadId);
339 | }
340 | else
341 | {
342 | /* the process was created as suspended, track the thread and only inject once it is resumed */
343 | this->suspendedThreads[lpProcessInformation->dwThreadId] = lpProcessInformation->dwProcessId;
344 | }
345 |
346 | return ret;
347 | }
348 |
349 | NTSTATUS WINAPI UnpackingEngine::onNtCreateThread(
350 | PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ProcessHandle,
351 | PCLIENT_ID ClientId, PCONTEXT ThreadContext, PINITIAL_TEB InitialTeb, BOOLEAN CreateSuspended)
352 | {
353 | if (this->hooksReady)
354 | Logger::getInstance()->write(LOG_INFO, "NtCreateThread(TargetPID %d, Entry 0x%08x)\n", GetProcessId(ProcessHandle), ThreadContext->Eip);
355 |
356 | if (this->hooksReady)
357 | {
358 | if (this->isSelfProcess(ProcessHandle))
359 | {
360 | /* the thread is in this process, check if it is starting on a tracked executable block */
361 | auto it = this->executableBlocks.findTracked(ThreadContext->Eip, 1);
362 | if (it != this->executableBlocks.nullMarker())
363 | {
364 | /* it's an executable block being tracked */
365 | /* set the block back to executable */
366 | ULONG _oldProtection;
367 | auto ret = this->origNtProtectVirtualMemory(GetCurrentProcess(), (PVOID*)&it->startAddress, (PULONG)&it->size, (DWORD)it->neededProtection, &_oldProtection);
368 | if (ret == 0)
369 | {
370 | /* dump the block and stop tracking it */
371 | this->blacklistedBlocks.startTracking(*it);
372 | this->dumpMemoryBlock(*it, ThreadContext->Eip);
373 | this->executableBlocks.stopTracking(it);
374 | }
375 | }
376 | }
377 | }
378 |
379 | return this->origNtCreateThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, ClientId, ThreadContext, InitialTeb, CreateSuspended);
380 | }
381 |
382 | NTSTATUS WINAPI UnpackingEngine::onNtMapViewOfSection(
383 | HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG ZeroBits, ULONG CommitSize,
384 | PLARGE_INTEGER SectionOffset, PULONG ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Protect)
385 | {
386 | if (this->hooksReady)
387 | Logger::getInstance()->write(LOG_INFO, "PRE-NtMapViewOfSection(TargetPID %d, Address 0x%08x, Size 0x%08x)\n", GetProcessId(ProcessHandle), (DWORD)*BaseAddress, (DWORD)*ViewSize);
388 |
389 | auto ret = this->origNtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize,
390 | SectionOffset, ViewSize, InheritDisposition, AllocationType, Protect);
391 |
392 | if (this->hooksReady)
393 | Logger::getInstance()->write(LOG_INFO, "PST-NtMapViewOfSection(TargetPID %d, Address is 0x%08x, Size 0x%08x) RET: 0x%08x\n", GetProcessId(ProcessHandle), (DWORD)*BaseAddress, (DWORD)*ViewSize, ret);
394 |
395 | if (ret == 0 && this->hooksReady)
396 | {
397 | DWORD targetPID = this->getProcessIdIfRemote(ProcessHandle);
398 | if (targetPID)
399 | {
400 | //TODO: clean this up, there's no reason we have to allocate a buffer and use an RPM() call.
401 | DWORD bytesRead;
402 | unsigned char* buffer = new unsigned char[(DWORD)*ViewSize];
403 | if (ReadProcessMemory(ProcessHandle, *BaseAddress, &buffer[0], (DWORD)*ViewSize, &bytesRead) && bytesRead > 0)
404 | {
405 | char fileName[MAX_PATH];
406 | sprintf(fileName, "C:\\dumps\\[%d]_%d_0x%08x_to_0x%08x.MVOS.DMP", targetPID, GetTickCount(), (DWORD)*BaseAddress, (DWORD)*BaseAddress + (DWORD)*ViewSize);
407 |
408 | this->dumpMemoryBlock(fileName, bytesRead, (const unsigned char*)buffer);
409 | }
410 | else
411 | Logger::getInstance()->write(LOG_ERROR, "Failed to ReadProcessMemory() from NtMapViewOfSection() hook! (Address is 0x%08x, Size is 0x%08x) (PID is %d)\n", (DWORD)*BaseAddress, (DWORD)*ViewSize, GetProcessId(ProcessHandle));
412 |
413 | delete [] buffer;
414 | }
415 | }
416 |
417 | return ret;
418 | }
419 |
420 | NTSTATUS WINAPI UnpackingEngine::onNtResumeThread(HANDLE thread, PULONG suspendCount)
421 | {
422 | auto threadId = GetThreadId(thread);
423 | if (this->suspendedThreads.find(threadId) != this->suspendedThreads.end())
424 | {
425 | auto targetPID = suspendedThreads[threadId];
426 | Logger::getInstance()->write(LOG_INFO, "Propogating into process %d from NtResumeThread() hook.\n", targetPID);
427 |
428 | auto targetHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, targetPID);
429 | if (targetHandle == INVALID_HANDLE_VALUE)
430 | Logger::getInstance()->write(LOG_ERROR, "FAILED to open process %d from NtResumeThread() hook!\n", targetPID);
431 | else
432 | {
433 | hooks->injectIntoProcess(targetHandle, L"PackerAttackerHook.dll");
434 | Logger::getInstance()->write(LOG_INFO, "Propogation into process %d from NtResumeThread() hook COMPLETE!\n", targetPID);
435 | }
436 |
437 | }
438 |
439 | return this->origNtResumeThread(thread, suspendCount);
440 | }
441 |
442 | NTSTATUS WINAPI UnpackingEngine::onNtDelayExecution(BOOLEAN alertable, PLARGE_INTEGER time)
443 | {
444 | Logger::getInstance()->write(LOG_INFO, "Sleep call detected (Low part: %d, High part: %d).", time->LowPart, time->HighPart);
445 |
446 | return this->origNtDelayExecution(alertable, time);
447 | }
448 |
449 | NTSTATUS WINAPI UnpackingEngine::onNtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG ZeroBits, PULONG RegionSize, ULONG AllocationType, ULONG Protect)
450 | {
451 | if (this->inAllocationHook)
452 | return this->origNtAllocateVirtualMemory(ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect);
453 |
454 | this->inAllocationHook = true;
455 | if (this->hooksReady)
456 | Logger::getInstance()->write(LOG_INFO, "PRE-NtAllocateVirtualMemory(TargetPID %d, Address 0x%08x, Size 0x%08x, Protection 0x%08x)\n", GetProcessId(ProcessHandle), (DWORD)*BaseAddress, (DWORD)*RegionSize, Protect);
457 |
458 | auto ret = this->origNtAllocateVirtualMemory(ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect);
459 |
460 | if (this->hooksReady)
461 | Logger::getInstance()->write(LOG_INFO, "PST-NtAllocateVirtualMemory(TargetPID %d, Address 0x%08x, Count 0x%08x, Protection 0x%08x) RET: 0x%08x\n", GetProcessId(ProcessHandle), (DWORD)*BaseAddress, (RegionSize) ? *RegionSize : 0, Protect, ret);
462 |
463 |
464 | if (ret == 0 && this->hooksReady && this->isSelfProcess(ProcessHandle))
465 | this->processMemoryBlockFromHook("onNtAllocateVirtualMemory", (DWORD)*BaseAddress, (DWORD)*RegionSize, Protect, NULL, false);
466 | this->inAllocationHook = false;
467 |
468 | return ret;
469 | }
470 |
471 | NTSTATUS NTAPI UnpackingEngine::onRtlDecompressBuffer(USHORT CompressionFormat, PUCHAR UncompressedBuffer, ULONG UncompressedBufferSize, PUCHAR CompressedBuffer, ULONG CompressedBufferSize, PULONG FinalUncompressedSize){
472 | Logger::getInstance()->write(LOG_INFO, "PRE-RtlDecompressBuffer (UncompressedBuffer: 0x%x)", (DWORD)UncompressedBuffer);
473 | auto ret = this->origRtlDecompressBuffer(CompressionFormat, UncompressedBuffer, UncompressedBufferSize, CompressedBuffer, CompressedBufferSize, FinalUncompressedSize);
474 | Logger::getInstance()->write(LOG_INFO, "PST-RtlDecompressBuffer (FinalUncompressedSize: 0x%x)", UncompressedBufferSize);
475 |
476 | char fileName[MAX_PATH];
477 | DWORD PID = GetCurrentProcessId();
478 |
479 | sprintf(fileName, "C:\\dumps\\[%d]_%d_0x%p_to_0x%p.RDB.DMP", PID, GetTickCount(), UncompressedBuffer, UncompressedBuffer + *FinalUncompressedSize);
480 | this->dumpMemoryBlock(fileName, *FinalUncompressedSize, UncompressedBuffer);
481 |
482 | return ret;
483 | }
484 |
485 | long UnpackingEngine::onShallowException(PEXCEPTION_POINTERS info)
486 | {
487 | // ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
488 | if (info->ExceptionRecord->ExceptionCode != STATUS_ACCESS_VIOLATION)
489 | return EXCEPTION_CONTINUE_SEARCH; /* only worried about access violations */
490 |
491 | if (info->ExceptionRecord->NumberParameters != 2)
492 | return EXCEPTION_CONTINUE_SEARCH; /* should have 2 params */
493 |
494 | bool isWriteException = (info->ExceptionRecord->ExceptionInformation[0] != 8);
495 | DWORD exceptionAddress = info->ExceptionRecord->ExceptionInformation[1];//(DWORD)info->ExceptionRecord->ExceptionAddress;
496 |
497 | if (isWriteException) /* monitor writes to tracked PE sections */
498 | {
499 | auto sg = this->lock->enterWithScopeGuard();
500 |
501 | auto it = this->writeablePEBlocks.findTracked(exceptionAddress, 1);
502 | if (it == this->writeablePEBlocks.nullMarker())
503 | {
504 | Logger::getInstance()->write(LOG_WARN, "STATUS_ACCESS_VIOLATION write on 0x%08x not treated as hook!", exceptionAddress);
505 | return EXCEPTION_CONTINUE_SEARCH; /* we're not tracking the page */
506 | }
507 |
508 | /* it's a PE section beign tracked */
509 | /* set the section back to writeable */
510 | ULONG _oldProtection;
511 | auto ret = this->origNtProtectVirtualMemory(GetCurrentProcess(), (PVOID*)&it->startAddress, (PULONG)&it->size, PAGE_READWRITE, &_oldProtection);
512 | if (ret != 0)
513 | {
514 | Logger::getInstance()->write(LOG_ERROR, "Failed to remove write hook on 0x%08x!", exceptionAddress);
515 | return EXCEPTION_CONTINUE_SEARCH; /* couldn't set page back to regular protection, wtf? */
516 | }
517 |
518 | /* start tracking execution in the section and stop tracking writes */
519 | this->executableBlocks.startTracking(*it);
520 | this->writeablePEBlocks.stopTracking(it);
521 |
522 | Logger::getInstance()->write(LOG_INFO, "STATUS_ACCESS_VIOLATION write on 0x%08x triggered write hook!", exceptionAddress);
523 |
524 | /* writing to the section should work now */
525 | return EXCEPTION_CONTINUE_EXECUTION;
526 | }
527 | else /* monitor executes to tracked executable blocks */
528 | {
529 | auto sg = this->lock->enterWithScopeGuard();
530 |
531 | auto it = this->executableBlocks.findTracked(exceptionAddress, 1);
532 | if (it == this->executableBlocks.nullMarker())
533 | {
534 | /* this isn't memory we've hooked, so this is an unrelated DEP exception.
535 | If the process didn't initially have DEP enabled, we should fix the protection so it can execute.
536 | If the process did initially have DEP enabled, we should let it crash as normal */
537 | if (this->simulateDisabledDEP)
538 | {
539 | ULONG _oldProtection;
540 | DWORD _address = exceptionAddress;
541 | ULONG _size = 1;
542 | auto ret = this->origNtProtectVirtualMemory(GetCurrentProcess(), (PVOID*)&_address, (PULONG)&_size, PAGE_EXECUTE_READWRITE, &_oldProtection);
543 | Logger::getInstance()->write(LOG_INFO, "STATUS_ACCESS_VIOLATION execute on 0x%08x (NOT A HOOK). Simulating DEP-lessness from 0x%08x to 0x%08x.", exceptionAddress, _address, _address + _size);
544 |
545 | return EXCEPTION_CONTINUE_EXECUTION;
546 | }
547 | else
548 | {
549 | Logger::getInstance()->write(LOG_INFO, "STATUS_ACCESS_VIOLATION execute on 0x%08x (NOT A HOOK). No need to simulate DEP-lessness.", exceptionAddress);
550 | return EXCEPTION_CONTINUE_SEARCH;
551 | }
552 | }
553 |
554 | /* it's an executable block being tracked */
555 | /* set the block back to executable */
556 | ULONG _oldProtection;
557 | auto ret = this->origNtProtectVirtualMemory(GetCurrentProcess(), (PVOID*)&it->startAddress, (PULONG)&it->size, (DWORD)it->neededProtection, &_oldProtection);
558 | if (ret != 0)
559 | {
560 | Logger::getInstance()->write(LOG_ERROR, "Failed to removed execute hook on 0x%08x!", exceptionAddress);
561 | return EXCEPTION_CONTINUE_SEARCH; /* couldn't set page back to executable, wtf? */
562 | }
563 |
564 | /* dump the block and stop tracking it */
565 | this->blacklistedBlocks.startTracking(*it);
566 | this->dumpMemoryBlock(*it, exceptionAddress);
567 | this->executableBlocks.stopTracking(it);
568 |
569 | Logger::getInstance()->write(LOG_INFO, "STATUS_ACCESS_VIOLATION execute on 0x%08x triggered execute hook!", exceptionAddress);
570 |
571 | /* execution should work now */
572 | return EXCEPTION_CONTINUE_EXECUTION;
573 | }
574 | }
575 |
576 |
577 | long UnpackingEngine::onDeepException(PEXCEPTION_POINTERS info)
578 | {
579 | const char* exceptionDesc = "unknown";
580 | if (info->ExceptionRecord->ExceptionCode == STATUS_WAIT_0) exceptionDesc = "STATUS_WAIT_0";
581 | else if (info->ExceptionRecord->ExceptionCode == STATUS_ABANDONED_WAIT_0) exceptionDesc = "STATUS_ABANDONED_WAIT_0";
582 | else if (info->ExceptionRecord->ExceptionCode == STATUS_USER_APC) exceptionDesc = "STATUS_USER_APC";
583 | else if (info->ExceptionRecord->ExceptionCode == STATUS_TIMEOUT) exceptionDesc = "STATUS_TIMEOUT";
584 | else if (info->ExceptionRecord->ExceptionCode == STATUS_PENDING) exceptionDesc = "STATUS_PENDING";
585 | else if (info->ExceptionRecord->ExceptionCode == DBG_EXCEPTION_HANDLED) exceptionDesc = "DBG_EXCEPTION_HANDLED";
586 | else if (info->ExceptionRecord->ExceptionCode == DBG_CONTINUE) exceptionDesc = "DBG_CONTINUE";
587 | else if (info->ExceptionRecord->ExceptionCode == STATUS_SEGMENT_NOTIFICATION) exceptionDesc = "STATUS_SEGMENT_NOTIFICATION";
588 | else if (info->ExceptionRecord->ExceptionCode == DBG_TERMINATE_THREAD) exceptionDesc = "DBG_TERMINATE_THREAD";
589 | else if (info->ExceptionRecord->ExceptionCode == DBG_TERMINATE_PROCESS) exceptionDesc = "DBG_TERMINATE_PROCESS";
590 | else if (info->ExceptionRecord->ExceptionCode == DBG_CONTROL_C) exceptionDesc = "DBG_CONTROL_C";
591 | else if (info->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) exceptionDesc = "DBG_PRINTEXCEPTION_C";
592 | else if (info->ExceptionRecord->ExceptionCode == DBG_RIPEXCEPTION) exceptionDesc = "DBG_RIPEXCEPTION";
593 | else if (info->ExceptionRecord->ExceptionCode == DBG_CONTROL_BREAK) exceptionDesc = "DBG_CONTROL_BREAK";
594 | else if (info->ExceptionRecord->ExceptionCode == DBG_COMMAND_EXCEPTION) exceptionDesc = "DBG_COMMAND_EXCEPTION";
595 | else if (info->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) exceptionDesc = "STATUS_GUARD_PAGE_VIOLATION";
596 | else if (info->ExceptionRecord->ExceptionCode == STATUS_DATATYPE_MISALIGNMENT) exceptionDesc = "STATUS_DATATYPE_MISALIGNMENT";
597 | else if (info->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) exceptionDesc = "STATUS_BREAKPOINT";
598 | else if (info->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP) exceptionDesc = "STATUS_SINGLE_STEP";
599 | else if (info->ExceptionRecord->ExceptionCode == STATUS_LONGJUMP) exceptionDesc = "STATUS_LONGJUMP";
600 | else if (info->ExceptionRecord->ExceptionCode == STATUS_UNWIND_CONSOLIDATE) exceptionDesc = "STATUS_UNWIND_CONSOLIDATE";
601 | else if (info->ExceptionRecord->ExceptionCode == DBG_EXCEPTION_NOT_HANDLED) exceptionDesc = "DBG_EXCEPTION_NOT_HANDLED";
602 | else if (info->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) exceptionDesc = "STATUS_ACCESS_VIOLATION";
603 | else if (info->ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR) exceptionDesc = "STATUS_IN_PAGE_ERROR";
604 | else if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_HANDLE) exceptionDesc = "STATUS_INVALID_HANDLE";
605 | else if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_PARAMETER) exceptionDesc = "STATUS_INVALID_PARAMETER";
606 | else if (info->ExceptionRecord->ExceptionCode == STATUS_NO_MEMORY) exceptionDesc = "STATUS_NO_MEMORY";
607 | else if (info->ExceptionRecord->ExceptionCode == STATUS_ILLEGAL_INSTRUCTION) exceptionDesc = "STATUS_ILLEGAL_INSTRUCTION";
608 | else if (info->ExceptionRecord->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION) exceptionDesc = "STATUS_NONCONTINUABLE_EXCEPTION";
609 | else if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_DISPOSITION) exceptionDesc = "STATUS_INVALID_DISPOSITION";
610 | else if (info->ExceptionRecord->ExceptionCode == STATUS_ARRAY_BOUNDS_EXCEEDED) exceptionDesc = "STATUS_ARRAY_BOUNDS_EXCEEDED";
611 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_DENORMAL_OPERAND) exceptionDesc = "STATUS_FLOAT_DENORMAL_OPERAND";
612 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_DIVIDE_BY_ZERO) exceptionDesc = "STATUS_FLOAT_DIVIDE_BY_ZERO";
613 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_INEXACT_RESULT) exceptionDesc = "STATUS_FLOAT_INEXACT_RESULT";
614 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_INVALID_OPERATION) exceptionDesc = "STATUS_FLOAT_INVALID_OPERATION";
615 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_OVERFLOW) exceptionDesc = "STATUS_FLOAT_OVERFLOW";
616 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_STACK_CHECK) exceptionDesc = "STATUS_FLOAT_STACK_CHECK";
617 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_UNDERFLOW) exceptionDesc = "STATUS_FLOAT_UNDERFLOW";
618 | else if (info->ExceptionRecord->ExceptionCode == STATUS_INTEGER_DIVIDE_BY_ZERO) exceptionDesc = "STATUS_INTEGER_DIVIDE_BY_ZERO";
619 | else if (info->ExceptionRecord->ExceptionCode == STATUS_INTEGER_OVERFLOW) exceptionDesc = "STATUS_INTEGER_OVERFLOW";
620 | else if (info->ExceptionRecord->ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION) exceptionDesc = "STATUS_PRIVILEGED_INSTRUCTION";
621 | else if (info->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) exceptionDesc = "STATUS_STACK_OVERFLOW";
622 | else if (info->ExceptionRecord->ExceptionCode == STATUS_DLL_NOT_FOUND) exceptionDesc = "STATUS_DLL_NOT_FOUND";
623 | else if (info->ExceptionRecord->ExceptionCode == STATUS_ORDINAL_NOT_FOUND) exceptionDesc = "STATUS_ORDINAL_NOT_FOUND";
624 | else if (info->ExceptionRecord->ExceptionCode == STATUS_ENTRYPOINT_NOT_FOUND) exceptionDesc = "STATUS_ENTRYPOINT_NOT_FOUND";
625 | else if (info->ExceptionRecord->ExceptionCode == STATUS_CONTROL_C_EXIT) exceptionDesc = "STATUS_CONTROL_C_EXIT";
626 | else if (info->ExceptionRecord->ExceptionCode == STATUS_DLL_INIT_FAILED) exceptionDesc = "STATUS_DLL_INIT_FAILED";
627 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS) exceptionDesc = "STATUS_FLOAT_MULTIPLE_FAULTS";
628 | else if (info->ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS) exceptionDesc = "STATUS_FLOAT_MULTIPLE_TRAPS";
629 | else if (info->ExceptionRecord->ExceptionCode == STATUS_REG_NAT_CONSUMPTION) exceptionDesc = "STATUS_REG_NAT_CONSUMPTION";
630 | else if (info->ExceptionRecord->ExceptionCode == STATUS_STACK_BUFFER_OVERRUN) exceptionDesc = "STATUS_STACK_BUFFER_OVERRUN";
631 | else if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_CRUNTIME_PARAMETER) exceptionDesc = "STATUS_INVALID_CRUNTIME_PARAMETER";
632 | else if (info->ExceptionRecord->ExceptionCode == STATUS_ASSERTION_FAILURE) exceptionDesc = "STATUS_ASSERTION_FAILURE";
633 |
634 |
635 | auto sg = this->lock->enterWithScopeGuard();
636 | this->ignoreHooks(true);
637 |
638 | Logger::getInstance()->write(LOG_ERROR, "POSSIBLE CRASH DETECTED!");
639 | Logger::getInstance()->write(LOG_APPENDLINE, "\t%s at 0x%08x", exceptionDesc, info->ExceptionRecord->ExceptionAddress);
640 | Logger::getInstance()->write(LOG_APPENDLINE, "\t%s", exceptionDesc);
641 | Logger::getInstance()->write(LOG_APPENDLINE, "Exception Params: %d", info->ExceptionRecord->NumberParameters);
642 | for (unsigned int i = 0; i < info->ExceptionRecord->NumberParameters; i++)
643 | Logger::getInstance()->write(LOG_APPENDLINE, "\t\tParam #%d: 0x%08x", i, info->ExceptionRecord->ExceptionInformation[i]);
644 | Logger::getInstance()->write(LOG_APPENDLINE, "\tEAX: 0x%08x", info->ContextRecord->Eax);
645 | Logger::getInstance()->write(LOG_APPENDLINE, "\tEBP: 0x%08x", info->ContextRecord->Ebp);
646 | Logger::getInstance()->write(LOG_APPENDLINE, "\tEBX: 0x%08x", info->ContextRecord->Ebx);
647 | Logger::getInstance()->write(LOG_APPENDLINE, "\tECX: 0x%08x", info->ContextRecord->Ecx);
648 | Logger::getInstance()->write(LOG_APPENDLINE, "\tEDI: 0x%08x", info->ContextRecord->Edi);
649 | Logger::getInstance()->write(LOG_APPENDLINE, "\tEDX: 0x%08x", info->ContextRecord->Edx);
650 | Logger::getInstance()->write(LOG_APPENDLINE, "\tESI: 0x%08x", info->ContextRecord->Esi);
651 | Logger::getInstance()->write(LOG_APPENDLINE, "\tESP: 0x%08x", info->ContextRecord->Esp);
652 | Logger::getInstance()->write(LOG_APPENDLINE, "\tEIP: 0x%08x", info->ContextRecord->Eip);
653 | Logger::getInstance()->write(LOG_APPENDLINE, "\tEFLAGS: 0x%08x", info->ContextRecord->EFlags);
654 |
655 | DebugStackTracer stackTracer(
656 | [=](std::string line) -> void
657 | {
658 | bool ignore =
659 | (line.find("ERROR:") != std::string::npos) ||
660 | (line.find("SymType:") != std::string::npos)||
661 | (line.find("SymInit:") != std::string::npos)||
662 | (line.find("OS-Version:") != std::string::npos);
663 |
664 | auto replaceString = [=](std::string& text, const std::string key, const std::string value) -> void
665 | {
666 | if (value.find(key) != std::string::npos)
667 | return;
668 | for (std::string::size_type keyStart = text.find(key); keyStart != std::string::npos; keyStart = text.find(key))
669 | text.replace(keyStart, key.size(), value);
670 | };
671 |
672 | if (!ignore)
673 | {
674 | replaceString(line, ": (filename not available)", "");
675 | replaceString(line, ": (function-name not available)", "");
676 | Logger::getInstance()->write(LOG_APPENDLINE, "\t\t%s", line.c_str());
677 | }
678 | }
679 | );
680 |
681 | Logger::getInstance()->write(LOG_APPENDLINE, "\tStack Trace:");
682 | stackTracer.ShowCallstack(GetCurrentThread(), info->ContextRecord);
683 | this->ignoreHooks(false);
684 |
685 |
686 | return EXCEPTION_CONTINUE_SEARCH;
687 | }
688 |
--------------------------------------------------------------------------------
/src/hook/UnpackingEngine.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "HookingEngine.h"
3 | #include "TrackedMemoryBlock.h"
4 | #include "SyncLock.h"
5 | #include "ntdefs.h"
6 |
7 | #include
8 | #include