├── .gitignore
├── LICENSE
├── README.md
├── SimpleOpt.h
├── dbgext.cxx
├── dbgext.hpp
├── dllmain.cxx
├── filter.cxx
├── gdiexts.cxx
├── handle.cxx
├── handle.hpp
├── help.cxx
├── object
├── palette.hpp
├── region.hpp
└── suface.hpp
├── stdafx.cpp
├── stdafx.h
├── targetver.h
├── utils.cxx
├── utils.hpp
├── win32kext.def
├── win32kext.sln
├── win32kext.vcxproj
└── win32kext.vcxproj.filters
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # win32kext
2 |
3 | windbg plugin for win32k debugging
4 |
5 | ## Usage
6 |
7 | ```
8 | gh [object handle] -- HMGR entry of handle (GDI object like DC/BITMAP/PALETTE etc)
9 | uh [object handle] -- USER entry of handle (USER object like WINDOW/MENU etc)
10 | duh [-h] -- Dump USER entry of handle (USER object like WINDOW/MENU etc)
11 | dgh [-h] -- Dump HMGR entry of handle (GDI object like DC/BITMAP/PALETTE etc)
12 | dpsurf [SURFACE ptr] -- SURFACE
13 | dpso [SURFOBJ ptr] -- SURFACE struct from SURFOBJ
14 | dr [REGION ptr] -- REGION
15 | cr [REGION ptr] -- check REGION
16 | dppal [PALETTE ptr] -- PALETTE
17 | help -- show help
18 | ```
19 |
20 | eg
21 |
22 | ```
23 | kd> !gh rcx
24 | Object Type DC(1)
25 | Handle 0x18010665
26 | Object 0xffffa03dc4838010
27 | kd> dq 0xffffa03dc4838010+1f8 l1
28 | ffffa03d`c4838208 ffffa03d`c02a4b00
29 | kd> !dpsurf ffffa03d`c02a4b00
30 | !!!WARNING!!!surface struct has been changed(our=(0x278, system=0x2b8) please check it.and the information may be wrong
31 | SURFACE structure at 0xffffa03dc02a4b00:
32 | --------------------------------------------------
33 | DHSURF dhsurf 0x0000000000000000
34 | HSURF hsurf 0x000000000005068a
35 | DHPDEV dhpdev 0x0000000000000000
36 | HDEV hdev 0xffffa03dc001c010
37 | SIZEL sizlBitmap.cx 0x63d
38 | SIZEL sizlBitmap.cy 0x32
39 | ULONG cjBits 0x4dfa8
40 | PVOID pvBits 0x00000000046e0000
41 | PVOID pvScan0 0x00000000046e0000
42 | LONG lDelta 0x18f4
43 | ULONG iUniq 0x940
44 | ULONG iBitmapFormat 0x6, BMF_32BPP
45 | USHORT iType 0x0, STYPE_BITMAP
46 | USHORT fjBitmap 0x811
47 | PPALETTE ppal 0xffffa03dc3d33e10
48 | --------------------------------------------------
49 | ```
50 |
51 | ```
52 | 1: kd> !duh -h
53 | Usage: !duh [args]
54 |
55 | args list:
56 | -p [process] filter object by process
57 | -t [type id] filter object by type id
58 | valid type:
59 | id:1 - Window
60 | id:2 - Menu
61 | id:3 - Cursor
62 | id:4 - DeferWindowPos
63 | id:5 - WindowHook
64 | id:6 - MemoryHandle
65 | id:7 - CPD
66 | id:8 - AcceleratorTable
67 | id:9 - CsDde
68 | id:10 - Conversation
69 | id:11 - pxs
70 | id:12 - Monitor
71 | id:13 - Keyboard
72 | id:14 - KeyboardLayout
73 | id:15 - EventHook
74 | id:16 - Timer
75 | id:17 - InputContext
76 | id:18 - HidData
77 | id:20 - TouchInputInfo
78 | id:21 - GestureInfo
79 | id:23 - BaseWindow
80 | example:
81 | !duh
82 | will dump user object in system
83 | !duh -p 0xffffffff13450080
84 | will dump user object create by process 0xffffffff13450080
85 | !duh -t 1
86 | will dump all window object
87 | !duh -t 1 -p 0xffffffff13450080
88 | will dump all window object create by process 0xffffffff13450080
89 |
90 | ```
91 |
92 | eg
93 |
94 | ```
95 | 1: kd> !duh
96 | Total 0x380 handles
97 | handle=0x00010002 object=0xffffa99640830000 process=0xffffc409f16d4080 type=(01)Window
98 | handle=0x00010003 object=0xffffa99640850000 process=0xffffc409f16d4080 type=(03)Cursor
99 | handle=0x00010004 object=0xffffa99640830150 process=0xffffc409f16d4080 type=(01)Window
100 | handle=0x00010005 object=0xffffa996408500a0 process=0xffffc409f16d4080 type=(03)Cursor
101 | handle=0x00010006 object=0xffffa996408302a0 process=0xffffc409f16d4080 type=(01)Window
102 |
103 | 1: kd> !duh -p 0xffffc409f16d4080 -t 1
104 | Total 0x380 handles
105 | handle=0x00010002 object=0xffffa99640830000 process=0xffffc409f16d4080 type=(01)Window
106 | handle=0x00010004 object=0xffffa99640830150 process=0xffffc409f16d4080 type=(01)Window
107 | handle=0x00010006 object=0xffffa996408302a0 process=0xffffc409f16d4080 type=(01)Window
108 | handle=0x00010008 object=0xffffa996408303f0 process=0xffffc409f16d4080 type=(01)Window
109 | handle=0x0001000a object=0xffffa99640830540 process=0xffffc409f16d4080 type=(01)Window
110 | handle=0x0001000c object=0xffffa99640830690 process=0xffffc409f16d4080 type=(01)Window
111 | user control-c break
112 |
113 | 1: kd> !duh -t 1
114 | Total 0x380 handles
115 | handle=0x00010002 object=0xffffa99640830000 process=0xffffc409f16d4080 type=(01)Window w
116 | handle=0x00020016 object=0xffffa99640832e70 process=0xffffc409f168e240 type=(01)Window
117 | handle=0x00020018 object=0xffffa99640832d20 process=0xffffc409e96c1080 type=(01)Window
118 | handle=0x0002001a object=0xffffa99640832bd0 process=0xffffc409e96c1080 type=(01)Window
119 | handle=0x0003001c object=0xffffa99640832a80 process=0xffffc409f168e240 type=(01)Window
120 | user control-c break
121 |
122 |
123 | ```
124 |
125 | ```
126 | 1: kd> !dgh -h
127 | Usage: !dgh [args]
128 |
129 | args list:
130 | -p [process] filter object by process
131 | -t [type id] filter object by type id
132 | valid type:
133 | id:1 - DC
134 | id:2 - ColorTransform
135 | id:4 - Rgn
136 | id:5 - Bitmap
137 | id:7 - Path
138 | id:8 - Palette
139 | id:9 - ColorSpace
140 | id:10 - Font
141 | id:14 - ColorTransform
142 | id:15 - Sprite
143 | id:16 - Brush
144 | id:18 - LogicSurface
145 | id:19 - Space
146 | id:21 - ServerMetafile
147 | id:28 - Driver
148 | id:138 - Font2
149 | example:
150 | !dgh
151 | will dump gdi object in system
152 | !dgh -p 0xffffffff13450080
153 | will dump gdi object create by process 0xffffffff13450080
154 | !dgh -t 5
155 | will dump all bitmap object
156 | !dgh -t 1 -p 0xffffffff13450080
157 | will dump all bitmap object create by process 0xffffffff13450080
158 |
159 | ```
160 |
161 | eg
162 |
163 | ```
164 | 1: kd> !dgh -t 5
165 | Handle:0x0085000f Object=0xffffa99640890000 Type=Bitmap(5) entry=0xffffa99640a00168 processx=0x0
166 | Handle:0x0005001d Object=0xffffa99640890580 Type=Bitmap(5) entry=0xffffa99640a002b8 processx=0x0
167 | Handle:0x00050031 Object=0xffffa996408902c0 Type=Bitmap(5) entry=0xffffa99640a00498 processx=0x0
168 | Handle:0x00050032 Object=0xffffa99640890840 Type=Bitmap(5) entry=0xffffa99640a004b0 processx=0x0
169 | Handle:0x00050033 Object=0xffffa99640890b00 Type=Bitmap(5) entry=0xffffa99640a004c8 processx=0x0
170 |
171 | 1: kd> !dgh
172 | Handle:0x0004000a Object=0xffffa99640602d00 Type=Rgn(4) entry=0xffffa99640a000f0 processx=0x0
173 | Handle:0x0088000b Object=0xffffa996408e0000 Type=Palette(8) entry=0xffffa99640a00108 processx=0x0
174 | Handle:0x0008000c Object=0xffffa996408e0090 Type=Palette(8) entry=0xffffa99640a00120 processx=0x0
175 | Handle:0x0008000d Object=0xffffa996408e0120 Type=Palette(8) entry=0xffffa99640a00138 processx=0x0
176 | Handle:0x0008000e Object=0xffffa996408e01b0 Type=Palette(8) entry=0xffffa99640a00150 processx=0x0
177 |
178 | ```
179 |
180 |
181 |
182 | ## Supported system
183 |
184 | !!!ONLY TEST ON!!!
185 | windows 10 1803 1903 64bits
186 |
187 | why not 32 bits?
188 |
189 | Guys you need change your Computer
190 |
191 | ## TODO
192 |
193 | - [ ] DC OBJECT
194 | - [ ] BRUSH OBJECT
195 | - [ ] WINDOW OBJECT
196 | - [ ] MENU OBJECT
197 | - [ ] PDEV OBJECT
198 | - [x] DUMP HANDLE
199 | - [ ] FONT OBJECT
200 | - [ ] DCOMP OBJECT
201 |
202 | ## Thanks to
203 |
204 | [SimpleOpt](https://github.com/brofield/simpleopt)
205 |
--------------------------------------------------------------------------------
/SimpleOpt.h:
--------------------------------------------------------------------------------
1 | /*! @file SimpleOpt.h
2 |
3 | @version 3.6
4 |
5 | @brief A cross-platform command line library which can parse almost any
6 | of the standard command line formats in use today. It is designed
7 | explicitly to be portable to any platform and has been tested on Windows
8 | and Linux. See CSimpleOptTempl for the class definition.
9 |
10 | @section features FEATURES
11 | - MIT Licence allows free use in all software (including GPL
12 | and commercial)
13 | - multi-platform (Windows 95/98/ME/NT/2K/XP, Linux, Unix)
14 | - supports all lengths of option names:
15 |
16 |
-
17 |
switch character only (e.g. use stdin for input)
18 |
-o
19 |
short (single character)
20 |
-long
21 |
long (multiple character, single switch character)
22 |
--longer
23 |
long (multiple character, multiple switch characters)
24 |
25 | - supports all types of arguments for options:
26 |
27 |
--option
28 |
short/long option flag (no argument)
29 |
--option ARG
30 |
short/long option with separate required argument
31 |
--option=ARG
32 |
short/long option with combined required argument
33 |
--option[=ARG]
34 |
short/long option with combined optional argument
35 |
-oARG
36 |
short option with combined required argument
37 |
-o[ARG]
38 |
short option with combined optional argument
39 |
40 | - supports options with multiple or variable numbers of arguments:
41 |
42 |
--multi ARG1 ARG2
43 |
Multiple arguments
44 |
--multi N ARG-1 ARG-2 ... ARG-N
45 |
Variable number of arguments
46 |
47 | - supports case-insensitive option matching on short, long and/or
48 | word arguments.
49 | - supports options which do not use a switch character. i.e. a special
50 | word which is construed as an option.
51 | e.g. "foo.exe open /directory/file.txt"
52 | - supports clumping of multiple short options (no arguments) in a string
53 | e.g. "foo.exe -abcdef file1" <==> "foo.exe -a -b -c -d -e -f file1"
54 | - automatic recognition of a single slash as equivalent to a single
55 | hyphen on Windows, e.g. "/f FILE" is equivalent to "-f FILE".
56 | - file arguments can appear anywhere in the argument list:
57 | "foo.exe file1.txt -a ARG file2.txt --flag file3.txt file4.txt"
58 | files will be returned to the application in the same order they were
59 | supplied on the command line
60 | - short-circuit option matching: "--man" will match "--mandate"
61 | invalid options can be handled while continuing to parse the command
62 | line valid options list can be changed dynamically during command line
63 | processing, i.e. accept different options depending on an option
64 | supplied earlier in the command line.
65 | - implemented with only a single C++ header file
66 | - optionally use no C runtime or OS functions
67 | - char, wchar_t and Windows TCHAR in the same program
68 | - complete working examples included
69 | - compiles cleanly at warning level 4 (Windows/VC.NET 2003), warning
70 | level 3 (Windows/VC6) and -Wall (Linux/gcc)
71 |
72 | @section usage USAGE
73 | The SimpleOpt class is used by following these steps:
74 |
75 |
Include the SimpleOpt.h header file
76 |
77 | \#include "SimpleOpt.h"
78 |
79 |
Define an array of valid options for your program.
80 |
90 | Note that all options must start with a hyphen even if the slash will
91 | be accepted. This is because the slash character is automatically
92 | converted into a hyphen to test against the list of options.
93 | For example, the following line matches both "-?" and "/?"
94 | (on Windows).
95 |
Process the arguments by calling Next() until it returns false.
104 | On each call, first check for an error by calling LastError(), then
105 | either handle the error or process the argument.
106 |
107 | while (args.Next()) {
108 | if (args.LastError() == SO_SUCCESS) {
109 | handle option: use OptionId(), OptionText() and OptionArg()
110 | }
111 | else {
112 | handle error: see ESOError enums
113 | }
114 | }
115 |
116 |
Process all non-option arguments with File(), Files() and FileCount()
117 |
121 |
122 | @section notes NOTES
123 | - In MBCS mode, this library is guaranteed to work correctly only when
124 | all option names use only ASCII characters.
125 | - Note that if case-insensitive matching is being used then the first
126 | matching option in the argument list will be returned.
127 |
128 | @section licence MIT LICENCE
129 |
130 | The licence text below is the boilerplate "MIT Licence" used from:
131 | http://www.opensource.org/licenses/mit-license.php
132 |
133 | Copyright (c) 2006-2013, Brodie Thiesfield
134 |
135 | Permission is hereby granted, free of charge, to any person obtaining a
136 | copy of this software and associated documentation files (the "Software"),
137 | to deal in the Software without restriction, including without limitation
138 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
139 | and/or sell copies of the Software, and to permit persons to whom the
140 | Software is furnished to do so, subject to the following conditions:
141 |
142 | The above copyright notice and this permission notice shall be included
143 | in all copies or substantial portions of the Software.
144 |
145 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
146 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
147 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
148 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
149 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
150 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
151 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
152 |
153 | */
154 |
155 | /*! @mainpage
156 |
157 |
158 |
Library
SimpleOpt
159 |
Author
Brodie Thiesfield [code at jellycan dot com]
160 |
Source
http://code.jellycan.com/simpleopt/
161 |
162 |
163 | @section SimpleOpt SimpleOpt
164 |
165 | A cross-platform library providing a simple method to parse almost any of
166 | the standard command-line formats in use today.
167 |
168 | See the @link SimpleOpt.h SimpleOpt @endlink documentation for full
169 | details.
170 |
171 | @section SimpleGlob SimpleGlob
172 |
173 | A cross-platform file globbing library providing the ability to
174 | expand wildcards in command-line arguments to a list of all matching
175 | files.
176 |
177 | See the @link SimpleGlob.h SimpleGlob @endlink documentation for full
178 | details.
179 | */
180 |
181 | #ifndef INCLUDED_SimpleOpt
182 | #define INCLUDED_SimpleOpt
183 |
184 | // Default the max arguments to a fixed value. If you want to be able to
185 | // handle any number of arguments, then predefine this to 0 and it will
186 | // use an internal dynamically allocated buffer instead.
187 | #ifdef SO_MAX_ARGS
188 | # define SO_STATICBUF SO_MAX_ARGS
189 | #else
190 | # include // malloc, free
191 | # include // memcpy
192 | # define SO_STATICBUF 50
193 | #endif
194 |
195 | //! Error values
196 | typedef enum _ESOError
197 | {
198 | //! No error
199 | SO_SUCCESS = 0,
200 |
201 | /*! It looks like an option (it starts with a switch character), but
202 | it isn't registered in the option table. */
203 | SO_OPT_INVALID = -1,
204 |
205 | /*! Multiple options matched the supplied option text.
206 | Only returned when NOT using SO_O_EXACT. */
207 | SO_OPT_MULTIPLE = -2,
208 |
209 | /*! Option doesn't take an argument, but a combined argument was
210 | supplied. */
211 | SO_ARG_INVALID = -3,
212 |
213 | /*! SO_REQ_CMB style-argument was supplied to a SO_REQ_SEP option
214 | Only returned when using SO_O_PEDANTIC. */
215 | SO_ARG_INVALID_TYPE = -4,
216 |
217 | //! Required argument was not supplied
218 | SO_ARG_MISSING = -5,
219 |
220 | /*! Option argument looks like another option.
221 | Only returned when NOT using SO_O_NOERR. */
222 | SO_ARG_INVALID_DATA = -6
223 | } ESOError;
224 |
225 | //! Option flags
226 | enum _ESOFlags
227 | {
228 | /*! Disallow partial matching of option names */
229 | SO_O_EXACT = 0x0001,
230 |
231 | /*! Disallow use of slash as an option marker on Windows.
232 | Un*x only ever recognizes a hyphen. */
233 | SO_O_NOSLASH = 0x0002,
234 |
235 | /*! Permit arguments on single letter options with no equals sign.
236 | e.g. -oARG or -o[ARG] */
237 | SO_O_SHORTARG = 0x0004,
238 |
239 | /*! Permit single character options to be clumped into a single
240 | option string. e.g. "-a -b -c" <==> "-abc" */
241 | SO_O_CLUMP = 0x0008,
242 |
243 | /*! Process the entire argv array for options, including the
244 | argv[0] entry. */
245 | SO_O_USEALL = 0x0010,
246 |
247 | /*! Do not generate an error for invalid options. errors for missing
248 | arguments will still be generated. invalid options will be
249 | treated as files. invalid options in clumps will be silently
250 | ignored. */
251 | SO_O_NOERR = 0x0020,
252 |
253 | /*! Validate argument type pedantically. Return an error when a
254 | separated argument "-opt arg" is supplied by the user as a
255 | combined argument "-opt=arg". By default this is not considered
256 | an error. */
257 | SO_O_PEDANTIC = 0x0040,
258 |
259 | /*! Case-insensitive comparisons for short arguments */
260 | SO_O_ICASE_SHORT = 0x0100,
261 |
262 | /*! Case-insensitive comparisons for long arguments */
263 | SO_O_ICASE_LONG = 0x0200,
264 |
265 | /*! Case-insensitive comparisons for word arguments
266 | i.e. arguments without any hyphens at the start. */
267 | SO_O_ICASE_WORD = 0x0400,
268 |
269 | /*! Case-insensitive comparisons for all arg types */
270 | SO_O_ICASE = 0x0700
271 | };
272 |
273 | /*! Types of arguments that options may have. Note that some of the _ESOFlags
274 | are not compatible with all argument types. SO_O_SHORTARG requires that
275 | relevant options use either SO_REQ_CMB or SO_OPT. SO_O_CLUMP requires
276 | that relevant options use only SO_NONE.
277 | */
278 | typedef enum _ESOArgType {
279 | /*! No argument. Just the option flags.
280 | e.g. -o --opt */
281 | SO_NONE,
282 |
283 | /*! Required separate argument.
284 | e.g. -o ARG --opt ARG */
285 | SO_REQ_SEP,
286 |
287 | /*! Required combined argument.
288 | e.g. -oARG -o=ARG --opt=ARG */
289 | SO_REQ_CMB,
290 |
291 | /*! Optional combined argument.
292 | e.g. -o[ARG] -o[=ARG] --opt[=ARG] */
293 | SO_OPT,
294 |
295 | /*! Multiple separate arguments. The actual number of arguments is
296 | determined programatically at the time the argument is processed.
297 | e.g. -o N ARG1 ARG2 ... ARGN --opt N ARG1 ARG2 ... ARGN */
298 | SO_MULTI
299 | } ESOArgType;
300 |
301 | //! this option definition must be the last entry in the table
302 | #define SO_END_OF_OPTIONS { -1, NULL, SO_NONE }
303 |
304 | #ifdef _DEBUG
305 | # ifdef _MSC_VER
306 | # include
307 | # define SO_ASSERT(b) _ASSERTE(b)
308 | # else
309 | # include
310 | # define SO_ASSERT(b) assert(b)
311 | # endif
312 | #else
313 | # define SO_ASSERT(b) //!< assertion used to test input data
314 | #endif
315 |
316 | // ---------------------------------------------------------------------------
317 | // MAIN TEMPLATE CLASS
318 | // ---------------------------------------------------------------------------
319 |
320 | /*! @brief Implementation of the SimpleOpt class */
321 | template
322 | class CSimpleOptTempl
323 | {
324 | public:
325 | /*! @brief Structure used to define all known options. */
326 | struct SOption {
327 | /*! ID to return for this flag. Optional but must be >= 0 */
328 | int nId;
329 |
330 | /*! arg string to search for, e.g. "open", "-", "-f", "--file"
331 | Note that on Windows the slash option marker will be converted
332 | to a hyphen so that "-f" will also match "/f". */
333 | const SOCHAR * pszArg;
334 |
335 | /*! type of argument accepted by this option */
336 | ESOArgType nArgType;
337 | };
338 |
339 | /*! @brief Initialize the class. Init() must be called later. */
340 | CSimpleOptTempl()
341 | : m_rgShuffleBuf(NULL)
342 | {
343 | Init(0, NULL, NULL, 0);
344 | }
345 |
346 | /*! @brief Initialize the class in preparation for use. */
347 | CSimpleOptTempl(
348 | int argc,
349 | SOCHAR * argv[],
350 | const SOption * a_rgOptions,
351 | int a_nFlags = 0
352 | )
353 | : m_rgShuffleBuf(NULL)
354 | {
355 | Init(argc, argv, a_rgOptions, a_nFlags);
356 | }
357 |
358 | #ifndef SO_MAX_ARGS
359 | /*! @brief Deallocate any allocated memory. */
360 | ~CSimpleOptTempl() { if (m_rgShuffleBuf) free(m_rgShuffleBuf); }
361 | #endif
362 |
363 | /*! @brief Initialize the class in preparation for calling Next.
364 |
365 | The table of options pointed to by a_rgOptions does not need to be
366 | valid at the time that Init() is called. However on every call to
367 | Next() the table pointed to must be a valid options table with the
368 | last valid entry set to SO_END_OF_OPTIONS.
369 |
370 | NOTE: the array pointed to by a_argv will be modified by this
371 | class and must not be used or modified outside of member calls to
372 | this class.
373 |
374 | @param a_argc Argument array size
375 | @param a_argv Argument array
376 | @param a_rgOptions Valid option array
377 | @param a_nFlags Optional flags to modify the processing of
378 | the arguments
379 |
380 | @return true Successful
381 | @return false if SO_MAX_ARGC > 0: Too many arguments
382 | if SO_MAX_ARGC == 0: Memory allocation failure
383 | */
384 | bool Init(
385 | int a_argc,
386 | SOCHAR * a_argv[],
387 | const SOption * a_rgOptions,
388 | int a_nFlags = 0
389 | );
390 |
391 | /*! @brief Change the current options table during option parsing.
392 |
393 | @param a_rgOptions Valid option array
394 | */
395 | inline void SetOptions(const SOption * a_rgOptions) {
396 | m_rgOptions = a_rgOptions;
397 | }
398 |
399 | /*! @brief Change the current flags during option parsing.
400 |
401 | Note that changing the SO_O_USEALL flag here will have no affect.
402 | It must be set using Init() or the constructor.
403 |
404 | @param a_nFlags Flags to modify the processing of the arguments
405 | */
406 | inline void SetFlags(int a_nFlags) { m_nFlags = a_nFlags; }
407 |
408 | /*! @brief Query if a particular flag is set */
409 | inline bool HasFlag(int a_nFlag) const {
410 | return (m_nFlags & a_nFlag) == a_nFlag;
411 | }
412 |
413 | /*! @brief Advance to the next option if available.
414 |
415 | When all options have been processed it will return false. When true
416 | has been returned, you must check for an invalid or unrecognized
417 | option using the LastError() method. This will be return an error
418 | value other than SO_SUCCESS on an error. All standard data
419 | (e.g. OptionText(), OptionArg(), OptionId(), etc) will be available
420 | depending on the error.
421 |
422 | After all options have been processed, the remaining files from the
423 | command line can be processed in same order as they were passed to
424 | the program.
425 |
426 | @return true option or error available for processing
427 | @return false all options have been processed
428 | */
429 | bool Next();
430 |
431 | /*! Stops processing of the command line and returns all remaining
432 | arguments as files. The next call to Next() will return false.
433 | */
434 | void Stop();
435 |
436 | /*! @brief Return the last error that occurred.
437 |
438 | This function must always be called before processing the current
439 | option. This function is available only when Next() has returned true.
440 | */
441 | inline ESOError LastError() const { return m_nLastError; }
442 |
443 | /*! @brief Return the nId value from the options array for the current
444 | option.
445 |
446 | This function is available only when Next() has returned true.
447 | */
448 | inline int OptionId() const { return m_nOptionId; }
449 |
450 | /*! @brief Return the pszArg from the options array for the current
451 | option.
452 |
453 | This function is available only when Next() has returned true.
454 | */
455 | inline const SOCHAR * OptionText() const { return m_pszOptionText; }
456 |
457 | /*! @brief Return the argument for the current option where one exists.
458 |
459 | If there is no argument for the option, this will return NULL.
460 | This function is available only when Next() has returned true.
461 | */
462 | inline SOCHAR * OptionArg() const { return m_pszOptionArg; }
463 |
464 | /*! @brief Validate and return the desired number of arguments.
465 |
466 | This is only valid when OptionId() has return the ID of an option
467 | that is registered as SO_MULTI. It may be called multiple times
468 | each time returning the desired number of arguments. Previously
469 | returned argument pointers are remain valid.
470 |
471 | If an error occurs during processing, NULL will be returned and
472 | the error will be available via LastError().
473 |
474 | @param n Number of arguments to return.
475 | */
476 | SOCHAR ** MultiArg(int n);
477 |
478 | /*! @brief Returned the number of entries in the Files() array.
479 |
480 | After Next() has returned false, this will be the list of files (or
481 | otherwise unprocessed arguments).
482 | */
483 | inline int FileCount() const { return m_argc - m_nLastArg; }
484 |
485 | /*! @brief Return the specified file argument.
486 |
487 | @param n Index of the file to return. This must be between 0
488 | and FileCount() - 1;
489 | */
490 | inline SOCHAR * File(int n) const {
491 | SO_ASSERT(n >= 0 && n < FileCount());
492 | return m_argv[m_nLastArg + n];
493 | }
494 |
495 | /*! @brief Return the array of files. */
496 | inline SOCHAR ** Files() const { return &m_argv[m_nLastArg]; }
497 |
498 | private:
499 | CSimpleOptTempl(const CSimpleOptTempl &); // disabled
500 | CSimpleOptTempl & operator=(const CSimpleOptTempl &); // disabled
501 |
502 | SOCHAR PrepareArg(SOCHAR * a_pszString) const;
503 | bool NextClumped();
504 | void ShuffleArg(int a_nStartIdx, int a_nCount);
505 | int LookupOption(const SOCHAR * a_pszOption) const;
506 | int CalcMatch(const SOCHAR *a_pszSource, const SOCHAR *a_pszTest) const;
507 |
508 | // Find the '=' character within a string.
509 | inline SOCHAR * FindEquals(SOCHAR *s) const {
510 | while (*s && *s != (SOCHAR)'=') ++s;
511 | return *s ? s : NULL;
512 | }
513 | bool IsEqual(SOCHAR a_cLeft, SOCHAR a_cRight, int a_nArgType) const;
514 |
515 | inline void Copy(SOCHAR ** ppDst, SOCHAR ** ppSrc, int nCount) const {
516 | #ifdef SO_MAX_ARGS
517 | // keep our promise of no CLIB usage
518 | while (nCount-- > 0) *ppDst++ = *ppSrc++;
519 | #else
520 | memcpy(ppDst, ppSrc, nCount * sizeof(SOCHAR*));
521 | #endif
522 | }
523 |
524 | private:
525 | const SOption * m_rgOptions; //!< pointer to options table
526 | int m_nFlags; //!< flags
527 | int m_nOptionIdx; //!< current argv option index
528 | int m_nOptionId; //!< id of current option (-1 = invalid)
529 | int m_nNextOption; //!< index of next option
530 | int m_nLastArg; //!< last argument, after this are files
531 | int m_argc; //!< argc to process
532 | SOCHAR ** m_argv; //!< argv
533 | const SOCHAR * m_pszOptionText; //!< curr option text, e.g. "-f"
534 | SOCHAR * m_pszOptionArg; //!< curr option arg, e.g. "c:\file.txt"
535 | SOCHAR * m_pszClump; //!< clumped single character options
536 | SOCHAR m_szShort[3]; //!< temp for clump and combined args
537 | ESOError m_nLastError; //!< error status from the last call
538 | SOCHAR ** m_rgShuffleBuf; //!< shuffle buffer for large argc
539 | };
540 |
541 | // ---------------------------------------------------------------------------
542 | // IMPLEMENTATION
543 | // ---------------------------------------------------------------------------
544 |
545 | template
546 | bool
547 | CSimpleOptTempl::Init(
548 | int a_argc,
549 | SOCHAR * a_argv[],
550 | const SOption * a_rgOptions,
551 | int a_nFlags
552 | )
553 | {
554 | m_argc = a_argc;
555 | m_nLastArg = a_argc;
556 | m_argv = a_argv;
557 | m_rgOptions = a_rgOptions;
558 | m_nLastError = SO_SUCCESS;
559 | m_nOptionIdx = 0;
560 | m_nOptionId = -1;
561 | m_pszOptionText = NULL;
562 | m_pszOptionArg = NULL;
563 | m_nNextOption = (a_nFlags & SO_O_USEALL) ? 0 : 1;
564 | m_szShort[0] = (SOCHAR)'-';
565 | m_szShort[2] = (SOCHAR)'\0';
566 | m_nFlags = a_nFlags;
567 | m_pszClump = NULL;
568 |
569 | #ifdef SO_MAX_ARGS
570 | if (m_argc > SO_MAX_ARGS) {
571 | m_nLastError = SO_ARG_INVALID_DATA;
572 | m_nLastArg = 0;
573 | return false;
574 | }
575 | #else
576 | if (m_rgShuffleBuf) {
577 | free(m_rgShuffleBuf);
578 | }
579 | if (m_argc > SO_STATICBUF) {
580 | m_rgShuffleBuf = (SOCHAR**) malloc(sizeof(SOCHAR*) * m_argc);
581 | if (!m_rgShuffleBuf) {
582 | return false;
583 | }
584 | }
585 | #endif
586 |
587 | return true;
588 | }
589 |
590 | template
591 | bool
592 | CSimpleOptTempl::Next()
593 | {
594 | #ifdef SO_MAX_ARGS
595 | if (m_argc > SO_MAX_ARGS) {
596 | SO_ASSERT(!"Too many args! Check the return value of Init()!");
597 | return false;
598 | }
599 | #endif
600 |
601 | // process a clumped option string if appropriate
602 | if (m_pszClump && *m_pszClump) {
603 | // silently discard invalid clumped option
604 | bool bIsValid = NextClumped();
605 | while (*m_pszClump && !bIsValid && HasFlag(SO_O_NOERR)) {
606 | bIsValid = NextClumped();
607 | }
608 |
609 | // return this option if valid or we are returning errors
610 | if (bIsValid || !HasFlag(SO_O_NOERR)) {
611 | return true;
612 | }
613 | }
614 | SO_ASSERT(!m_pszClump || !*m_pszClump);
615 | m_pszClump = NULL;
616 |
617 | // init for the next option
618 | m_nOptionIdx = m_nNextOption;
619 | m_nOptionId = -1;
620 | m_pszOptionText = NULL;
621 | m_pszOptionArg = NULL;
622 | m_nLastError = SO_SUCCESS;
623 |
624 | // find the next option
625 | SOCHAR cFirst;
626 | int nTableIdx = -1;
627 | int nOptIdx = m_nOptionIdx;
628 | while (nTableIdx < 0 && nOptIdx < m_nLastArg) {
629 | SOCHAR * pszArg = m_argv[nOptIdx];
630 | m_pszOptionArg = NULL;
631 |
632 | // find this option in the options table
633 | cFirst = PrepareArg(pszArg);
634 | if (pszArg[0] == (SOCHAR)'-') {
635 | // find any combined argument string and remove equals sign
636 | m_pszOptionArg = FindEquals(pszArg);
637 | if (m_pszOptionArg) {
638 | *m_pszOptionArg++ = (SOCHAR)'\0';
639 | }
640 | }
641 | nTableIdx = LookupOption(pszArg);
642 |
643 | // if we didn't find this option but if it is a short form
644 | // option then we try the alternative forms
645 | if (nTableIdx < 0
646 | && !m_pszOptionArg
647 | && pszArg[0] == (SOCHAR)'-'
648 | && pszArg[1]
649 | && pszArg[1] != (SOCHAR)'-'
650 | && pszArg[2])
651 | {
652 | // test for a short-form with argument if appropriate
653 | if (HasFlag(SO_O_SHORTARG)) {
654 | m_szShort[1] = pszArg[1];
655 | int nIdx = LookupOption(m_szShort);
656 | if (nIdx >= 0
657 | && (m_rgOptions[nIdx].nArgType == SO_REQ_CMB
658 | || m_rgOptions[nIdx].nArgType == SO_OPT))
659 | {
660 | m_pszOptionArg = &pszArg[2];
661 | pszArg = m_szShort;
662 | nTableIdx = nIdx;
663 | }
664 | }
665 |
666 | // test for a clumped short-form option string and we didn't
667 | // match on the short-form argument above
668 | if (nTableIdx < 0 && HasFlag(SO_O_CLUMP)) {
669 | m_pszClump = &pszArg[1];
670 | ++m_nNextOption;
671 | if (nOptIdx > m_nOptionIdx) {
672 | ShuffleArg(m_nOptionIdx, nOptIdx - m_nOptionIdx);
673 | }
674 | return Next();
675 | }
676 | }
677 |
678 | // The option wasn't found. If it starts with a switch character
679 | // and we are not suppressing errors for invalid options then it
680 | // is reported as an error, otherwise it is data.
681 | if (nTableIdx < 0) {
682 | if (!HasFlag(SO_O_NOERR) && pszArg[0] == (SOCHAR)'-') {
683 | m_pszOptionText = pszArg;
684 | break;
685 | }
686 |
687 | pszArg[0] = cFirst;
688 | ++nOptIdx;
689 | if (m_pszOptionArg) {
690 | *(--m_pszOptionArg) = (SOCHAR)'=';
691 | }
692 | }
693 | }
694 |
695 | // end of options
696 | if (nOptIdx >= m_nLastArg) {
697 | if (nOptIdx > m_nOptionIdx) {
698 | ShuffleArg(m_nOptionIdx, nOptIdx - m_nOptionIdx);
699 | }
700 | return false;
701 | }
702 | ++m_nNextOption;
703 |
704 | // get the option id
705 | ESOArgType nArgType = SO_NONE;
706 | if (nTableIdx < 0) {
707 | m_nLastError = (ESOError) nTableIdx; // error code
708 | }
709 | else {
710 | m_nOptionId = m_rgOptions[nTableIdx].nId;
711 | m_pszOptionText = m_rgOptions[nTableIdx].pszArg;
712 |
713 | // ensure that the arg type is valid
714 | nArgType = m_rgOptions[nTableIdx].nArgType;
715 | switch (nArgType) {
716 | case SO_NONE:
717 | if (m_pszOptionArg) {
718 | m_nLastError = SO_ARG_INVALID;
719 | }
720 | break;
721 |
722 | case SO_REQ_SEP:
723 | if (m_pszOptionArg) {
724 | // they wanted separate args, but we got a combined one,
725 | // unless we are pedantic, just accept it.
726 | if (HasFlag(SO_O_PEDANTIC)) {
727 | m_nLastError = SO_ARG_INVALID_TYPE;
728 | }
729 | }
730 | // more processing after we shuffle
731 | break;
732 |
733 | case SO_REQ_CMB:
734 | if (!m_pszOptionArg) {
735 | m_nLastError = SO_ARG_MISSING;
736 | }
737 | break;
738 |
739 | case SO_OPT:
740 | // nothing to do
741 | break;
742 |
743 | case SO_MULTI:
744 | // nothing to do. Caller must now check for valid arguments
745 | // using GetMultiArg()
746 | break;
747 | }
748 | }
749 |
750 | // shuffle the files out of the way
751 | if (nOptIdx > m_nOptionIdx) {
752 | ShuffleArg(m_nOptionIdx, nOptIdx - m_nOptionIdx);
753 | }
754 |
755 | // we need to return the separate arg if required, just re-use the
756 | // multi-arg code because it all does the same thing
757 | if ( nArgType == SO_REQ_SEP
758 | && !m_pszOptionArg
759 | && m_nLastError == SO_SUCCESS)
760 | {
761 | SOCHAR ** ppArgs = MultiArg(1);
762 | if (ppArgs) {
763 | m_pszOptionArg = *ppArgs;
764 | }
765 | }
766 |
767 | return true;
768 | }
769 |
770 | template
771 | void
772 | CSimpleOptTempl::Stop()
773 | {
774 | if (m_nNextOption < m_nLastArg) {
775 | ShuffleArg(m_nNextOption, m_nLastArg - m_nNextOption);
776 | }
777 | }
778 |
779 | template
780 | SOCHAR
781 | CSimpleOptTempl::PrepareArg(
782 | SOCHAR * a_pszString
783 | ) const
784 | {
785 | #ifdef _WIN32
786 | // On Windows we can accept the forward slash as a single character
787 | // option delimiter, but it cannot replace the '-' option used to
788 | // denote stdin. On Un*x paths may start with slash so it may not
789 | // be used to start an option.
790 | if (!HasFlag(SO_O_NOSLASH)
791 | && a_pszString[0] == (SOCHAR)'/'
792 | && a_pszString[1]
793 | && a_pszString[1] != (SOCHAR)'-')
794 | {
795 | a_pszString[0] = (SOCHAR)'-';
796 | return (SOCHAR)'/';
797 | }
798 | #endif
799 | return a_pszString[0];
800 | }
801 |
802 | template
803 | bool
804 | CSimpleOptTempl::NextClumped()
805 | {
806 | // prepare for the next clumped option
807 | m_szShort[1] = *m_pszClump++;
808 | m_nOptionId = -1;
809 | m_pszOptionText = NULL;
810 | m_pszOptionArg = NULL;
811 | m_nLastError = SO_SUCCESS;
812 |
813 | // lookup this option, ensure that we are using exact matching
814 | int nSavedFlags = m_nFlags;
815 | m_nFlags = SO_O_EXACT;
816 | int nTableIdx = LookupOption(m_szShort);
817 | m_nFlags = nSavedFlags;
818 |
819 | // unknown option
820 | if (nTableIdx < 0) {
821 | m_pszOptionText = m_szShort; // invalid option
822 | m_nLastError = (ESOError) nTableIdx; // error code
823 | return false;
824 | }
825 |
826 | // valid option
827 | m_pszOptionText = m_rgOptions[nTableIdx].pszArg;
828 | ESOArgType nArgType = m_rgOptions[nTableIdx].nArgType;
829 | if (nArgType == SO_NONE) {
830 | m_nOptionId = m_rgOptions[nTableIdx].nId;
831 | return true;
832 | }
833 |
834 | if (nArgType == SO_REQ_CMB && *m_pszClump) {
835 | m_nOptionId = m_rgOptions[nTableIdx].nId;
836 | m_pszOptionArg = m_pszClump;
837 | while (*m_pszClump) ++m_pszClump; // must point to an empty string
838 | return true;
839 | }
840 |
841 | // invalid option as it requires an argument
842 | m_nLastError = SO_ARG_MISSING;
843 | return true;
844 | }
845 |
846 | // Shuffle arguments to the end of the argv array.
847 | //
848 | // For example:
849 | // argv[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8" };
850 | //
851 | // ShuffleArg(1, 1) = { "0", "2", "3", "4", "5", "6", "7", "8", "1" };
852 | // ShuffleArg(5, 2) = { "0", "1", "2", "3", "4", "7", "8", "5", "6" };
853 | // ShuffleArg(2, 4) = { "0", "1", "6", "7", "8", "2", "3", "4", "5" };
854 | template
855 | void
856 | CSimpleOptTempl::ShuffleArg(
857 | int a_nStartIdx,
858 | int a_nCount
859 | )
860 | {
861 | SOCHAR * staticBuf[SO_STATICBUF];
862 | SOCHAR ** buf = m_rgShuffleBuf ? m_rgShuffleBuf : staticBuf;
863 | int nTail = m_argc - a_nStartIdx - a_nCount;
864 |
865 | // make a copy of the elements to be moved
866 | Copy(buf, m_argv + a_nStartIdx, a_nCount);
867 |
868 | // move the tail down
869 | Copy(m_argv + a_nStartIdx, m_argv + a_nStartIdx + a_nCount, nTail);
870 |
871 | // append the moved elements to the tail
872 | Copy(m_argv + a_nStartIdx + nTail, buf, a_nCount);
873 |
874 | // update the index of the last unshuffled arg
875 | m_nLastArg -= a_nCount;
876 | }
877 |
878 | // match on the long format strings. partial matches will be
879 | // accepted only if that feature is enabled.
880 | template
881 | int
882 | CSimpleOptTempl::LookupOption(
883 | const SOCHAR * a_pszOption
884 | ) const
885 | {
886 | int nBestMatch = -1; // index of best match so far
887 | int nBestMatchLen = 0; // matching characters of best match
888 | int nLastMatchLen = 0; // matching characters of last best match
889 |
890 | for (int n = 0; m_rgOptions[n].nId >= 0; ++n) {
891 | // the option table must use hyphens as the option character,
892 | // the slash character is converted to a hyphen for testing.
893 | SO_ASSERT(m_rgOptions[n].pszArg[0] != (SOCHAR)'/');
894 |
895 | int nMatchLen = CalcMatch(m_rgOptions[n].pszArg, a_pszOption);
896 | if (nMatchLen == -1) {
897 | return n;
898 | }
899 | if (nMatchLen > 0 && nMatchLen >= nBestMatchLen) {
900 | nLastMatchLen = nBestMatchLen;
901 | nBestMatchLen = nMatchLen;
902 | nBestMatch = n;
903 | }
904 | }
905 |
906 | // only partial matches or no match gets to here, ensure that we
907 | // don't return a partial match unless it is a clear winner
908 | if (HasFlag(SO_O_EXACT) || nBestMatch == -1) {
909 | return SO_OPT_INVALID;
910 | }
911 | return (nBestMatchLen > nLastMatchLen) ? nBestMatch : SO_OPT_MULTIPLE;
912 | }
913 |
914 | // calculate the number of characters that match (case-sensitive)
915 | // 0 = no match, > 0 == number of characters, -1 == perfect match
916 | template
917 | int
918 | CSimpleOptTempl::CalcMatch(
919 | const SOCHAR * a_pszSource,
920 | const SOCHAR * a_pszTest
921 | ) const
922 | {
923 | if (!a_pszSource || !a_pszTest) {
924 | return 0;
925 | }
926 |
927 | // determine the argument type
928 | int nArgType = SO_O_ICASE_LONG;
929 | if (a_pszSource[0] != '-') {
930 | nArgType = SO_O_ICASE_WORD;
931 | }
932 | else if (a_pszSource[1] != '-' && !a_pszSource[2]) {
933 | nArgType = SO_O_ICASE_SHORT;
934 | }
935 |
936 | // match and skip leading hyphens
937 | while (*a_pszSource == (SOCHAR)'-' && *a_pszSource == *a_pszTest) {
938 | ++a_pszSource;
939 | ++a_pszTest;
940 | }
941 | if (*a_pszSource == (SOCHAR)'-' || *a_pszTest == (SOCHAR)'-') {
942 | return 0;
943 | }
944 |
945 | // find matching number of characters in the strings
946 | int nLen = 0;
947 | while (*a_pszSource && IsEqual(*a_pszSource, *a_pszTest, nArgType)) {
948 | ++a_pszSource;
949 | ++a_pszTest;
950 | ++nLen;
951 | }
952 |
953 | // if we have exhausted the source...
954 | if (!*a_pszSource) {
955 | // and the test strings, then it's a perfect match
956 | if (!*a_pszTest) {
957 | return -1;
958 | }
959 |
960 | // otherwise the match failed as the test is longer than
961 | // the source. i.e. "--mant" will not match the option "--man".
962 | return 0;
963 | }
964 |
965 | // if we haven't exhausted the test string then it is not a match
966 | // i.e. "--mantle" will not best-fit match to "--mandate" at all.
967 | if (*a_pszTest) {
968 | return 0;
969 | }
970 |
971 | // partial match to the current length of the test string
972 | return nLen;
973 | }
974 |
975 | template
976 | bool
977 | CSimpleOptTempl::IsEqual(
978 | SOCHAR a_cLeft,
979 | SOCHAR a_cRight,
980 | int a_nArgType
981 | ) const
982 | {
983 | // if this matches then we are doing case-insensitive matching
984 | if (m_nFlags & a_nArgType) {
985 | if (a_cLeft >= 'A' && a_cLeft <= 'Z') a_cLeft += 'a' - 'A';
986 | if (a_cRight >= 'A' && a_cRight <= 'Z') a_cRight += 'a' - 'A';
987 | }
988 | return a_cLeft == a_cRight;
989 | }
990 |
991 | // calculate the number of characters that match (case-sensitive)
992 | // 0 = no match, > 0 == number of characters, -1 == perfect match
993 | template
994 | SOCHAR **
995 | CSimpleOptTempl::MultiArg(
996 | int a_nCount
997 | )
998 | {
999 | // ensure we have enough arguments
1000 | if (m_nNextOption + a_nCount > m_nLastArg) {
1001 | m_nLastError = SO_ARG_MISSING;
1002 | return NULL;
1003 | }
1004 |
1005 | // our argument array
1006 | SOCHAR ** rgpszArg = &m_argv[m_nNextOption];
1007 |
1008 | // Ensure that each of the following don't start with an switch character.
1009 | // Only make this check if we are returning errors for unknown arguments.
1010 | if (!HasFlag(SO_O_NOERR)) {
1011 | for (int n = 0; n < a_nCount; ++n) {
1012 | SOCHAR ch = PrepareArg(rgpszArg[n]);
1013 | if (rgpszArg[n][0] == (SOCHAR)'-') {
1014 | rgpszArg[n][0] = ch;
1015 | m_nLastError = SO_ARG_INVALID_DATA;
1016 | return NULL;
1017 | }
1018 | rgpszArg[n][0] = ch;
1019 | }
1020 | }
1021 |
1022 | // all good
1023 | m_nNextOption += a_nCount;
1024 | return rgpszArg;
1025 | }
1026 |
1027 |
1028 | // ---------------------------------------------------------------------------
1029 | // TYPE DEFINITIONS
1030 | // ---------------------------------------------------------------------------
1031 |
1032 | /*! @brief ASCII/MBCS version of CSimpleOpt */
1033 | typedef CSimpleOptTempl CSimpleOptA;
1034 |
1035 | /*! @brief wchar_t version of CSimpleOpt */
1036 | typedef CSimpleOptTempl CSimpleOptW;
1037 |
1038 | #if defined(_UNICODE)
1039 | /*! @brief TCHAR version dependent on if _UNICODE is defined */
1040 | # define CSimpleOpt CSimpleOptW
1041 | #else
1042 | /*! @brief TCHAR version dependent on if _UNICODE is defined */
1043 | # define CSimpleOpt CSimpleOptA
1044 | #endif
1045 |
1046 | #endif // INCLUDED_SimpleOpt
1047 |
--------------------------------------------------------------------------------
/dbgext.cxx:
--------------------------------------------------------------------------------
1 |
2 | #include "stdafx.h"
3 | #include "dbgext.hpp"
4 |
5 |
6 | PDEBUG_CLIENT4 g_ExtClient;
7 | PDEBUG_CONTROL4 g_ExtControl;
8 | PDEBUG_SYMBOLS2 g_ExtSymbols;
9 |
10 | WINDBG_EXTENSION_APIS ExtensionApis;
11 |
12 | ULONG TargetMachine;
13 | BOOL Connected;
14 |
15 | // Queries for all debugger interfaces.
16 | extern "C" HRESULT
17 | ExtQuery(PDEBUG_CLIENT4 Client)
18 | {
19 | HRESULT Status;
20 |
21 | if ((Status = Client->QueryInterface(__uuidof(IDebugControl4),
22 | (void**)&g_ExtControl)) != S_OK)
23 | {
24 | goto Fail;
25 | }
26 | if ((Status = Client->QueryInterface(__uuidof(IDebugSymbols2),
27 | (void**)&g_ExtSymbols)) != S_OK)
28 | {
29 | goto Fail;
30 | }
31 | g_ExtClient = Client;
32 |
33 | return S_OK;
34 |
35 | Fail:
36 | ExtRelease();
37 | return Status;
38 | }
39 |
40 | // Cleans up all debugger interfaces.
41 | void
42 | ExtRelease(void)
43 | {
44 | g_ExtClient = NULL;
45 | EXT_RELEASE(g_ExtControl);
46 | EXT_RELEASE(g_ExtSymbols);
47 | }
48 |
49 |
50 | // Normal output.
51 | void __cdecl
52 | ExtOut(PCSTR Format, ...)
53 | {
54 | va_list Args;
55 |
56 | va_start(Args, Format);
57 | g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
58 | va_end(Args);
59 | }
60 |
61 | // Error output.
62 | void __cdecl
63 | ExtErr(PCSTR Format, ...)
64 | {
65 | va_list Args;
66 |
67 | va_start(Args, Format);
68 | g_ExtControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args);
69 | va_end(Args);
70 | }
71 |
72 | // Warning output.
73 | void __cdecl
74 | ExtWarn(PCSTR Format, ...)
75 | {
76 | va_list Args;
77 |
78 | va_start(Args, Format);
79 | g_ExtControl->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args);
80 | va_end(Args);
81 | }
82 |
83 | void __cdecl
84 | ExtOutDml(PCSTR Format, ...)
85 | {
86 | va_list Args;
87 |
88 | va_start(Args, Format);
89 | g_ExtControl->ControlledOutputVaList(DEBUG_OUTCTL_DML, DEBUG_OUTPUT_NORMAL, Format, Args);
90 | va_end(Args);
91 | }
92 |
93 | EXTERN_C
94 | WIN32KEXT_API
95 | HRESULT
96 | CALLBACK
97 | DebugExtensionInitialize(
98 | OUT PULONG Version,
99 | OUT PULONG Flags)
100 | {
101 | IDebugClient* DebugClient;
102 | PDEBUG_CONTROL4 DebugControl;
103 | HRESULT hr = S_OK;
104 |
105 | *Version = DEBUG_EXTENSION_VERSION(1, 0);
106 | *Flags = 0;
107 |
108 | //
109 | // Create a new debugclient
110 | //
111 |
112 | if ((hr = DebugCreate(__uuidof(IDebugClient), (void**)&DebugClient)) != S_OK) {
113 | return hr;
114 | }
115 |
116 | if ((hr = DebugClient->QueryInterface(__uuidof(IDebugControl),
117 | (void**)&DebugControl)) == S_OK){
118 |
119 | //
120 | // Get the windbg-style extension APIS
121 | //
122 |
123 | ExtensionApis.nSize = sizeof(ExtensionApis);
124 | hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis);
125 |
126 | //
127 | // check is in kernel mode
128 | //
129 |
130 | ULONG dbgClass, dbgQualifier;
131 | if (SUCCEEDED(DebugControl->GetDebuggeeType(&dbgClass, &dbgQualifier))) {
132 | if (dbgClass != DEBUG_CLASS_KERNEL) {
133 | dprintf("This extension is for kernel-mode only\n");
134 | hr = S_FALSE;
135 | }
136 | }
137 |
138 | //
139 | // check os
140 | //
141 |
142 | ULONG PlatformId, Win32Major, Win32Minor, KdMajor, KdMinor;
143 | if (SUCCEEDED(DebugControl->GetSystemVersionValues(&PlatformId, &Win32Major, &Win32Minor,
144 | &KdMajor, &KdMinor))) {
145 | DEBUGPRINT("OS Detected: %d.%d.%d.%d\n", Win32Major, Win32Minor, KdMajor, KdMinor);
146 | }
147 |
148 | DebugControl->Release();
149 |
150 | }
151 | DebugClient->Release();
152 | return hr;
153 | }
154 |
155 | EXTERN_C
156 | WIN32KEXT_API
157 | void
158 | CALLBACK
159 | DebugExtensionUninitialize(void)
160 | {
161 | //DEBUGPRINT("DebugExtensionUninitialize\n");
162 | return;
163 | }
--------------------------------------------------------------------------------
/dbgext.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifndef IfFailedReturn
4 | #define IfFailedReturn(EXPR) do { hr = (EXPR); if (FAILED(hr)) { return hr; }} while(FALSE, FALSE)
5 | #endif // IfFailedReturn
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 |
12 | #define INIT_API() \
13 | HRESULT Status; \
14 | if ((Status = ExtQuery(Client)) != S_OK) return Status;
15 |
16 | #define EXT_RELEASE(Unk) \
17 | ((Unk) != NULL ? ((Unk)->Release(), (Unk) = NULL) : NULL)
18 |
19 | #define EXIT_API ExtRelease
20 |
21 |
22 | // Global variables initialized by query.
23 | extern PDEBUG_CLIENT4 g_ExtClient;
24 | extern PDEBUG_CONTROL4 g_ExtControl;
25 | extern PDEBUG_SYMBOLS2 g_ExtSymbols;
26 |
27 | extern BOOL Connected;
28 | extern ULONG TargetMachine;
29 |
30 | HRESULT
31 | ExtQuery(PDEBUG_CLIENT4 Client);
32 |
33 | void
34 | ExtRelease(void);
35 |
36 | void __cdecl
37 | ExtOutDml(PCSTR Format, ...);
38 |
39 | #ifdef __cplusplus
40 | }
41 | #endif
--------------------------------------------------------------------------------
/dllmain.cxx:
--------------------------------------------------------------------------------
1 | // dllmain.cpp : Defines the entry point for the DLL application.
2 | #include "stdafx.h"
3 |
4 | BOOL APIENTRY DllMain( HMODULE hModule,
5 | DWORD ul_reason_for_call,
6 | LPVOID lpReserved
7 | )
8 | {
9 | switch (ul_reason_for_call)
10 | {
11 | case DLL_PROCESS_ATTACH:
12 | case DLL_THREAD_ATTACH:
13 | case DLL_THREAD_DETACH:
14 | case DLL_PROCESS_DETACH:
15 | break;
16 | }
17 | return TRUE;
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/filter.cxx:
--------------------------------------------------------------------------------
1 |
2 | #include "stdafx.h"
3 | #include
4 |
5 | typedef struct _SYSCALL_FILTER
6 | {
7 | LPSTR *lpFuncName;
8 | ULONGLONG nCounts;
9 | }SYSCALL_FILTER, *PSYSCALL_FILTER;
10 |
11 | BOOL gFilterListInit = FALSE;
12 | SYSCALL_FILTER gSyscallFilterList[7] = {0};
13 |
14 | typedef enum _FILTER_LEVEL
15 | {
16 | NormalAPP = 0x0,
17 | Rs1RestrictedAppcontainer = 0x1,
18 | Rs1RestrictedAppcontainerPlugin = 0x2,
19 | FontDrvHost = 0x3,
20 | Rs1RestrictedAppcontainerMiniPlugin = 0x4,
21 | Rs3RestrictedAppcontainer = 0x5,
22 | Rs3HvsiRdpClient = 0x6,
23 | }FILTER_LEVEL;
24 |
25 |
26 | BOOL
27 | ReadString(
28 | WDBG_PTR ppstr,
29 | std::string &strRead
30 | )
31 | {
32 | int i = 0;
33 |
34 | strRead = "";
35 | while (1)
36 | {
37 | CHAR c;
38 | if(!ReadMemory((ULONG_PTR)ppstr + i, &c, 1, NULL)){
39 | return FALSE;
40 | }
41 |
42 | if (!c){
43 | break;
44 | }
45 |
46 | strRead += c;
47 | i++;
48 | }
49 |
50 | return TRUE;
51 | }
52 |
53 | EXTERN_C
54 | HRESULT CALLBACK
55 | fl(PDEBUG_CLIENT4 Client, PCSTR args)
56 | {
57 | ULONG Offset;
58 | ULONG FilterSet = 0;
59 |
60 | if (!gFilterListInit){
61 |
62 | //
63 | // read from win32kbase
64 | //
65 |
66 | WDBG_PTR kgSharedInfo = GetExpression("win32kbase!gaWin32KSyscallList");
67 |
68 | ReadMemory(kgSharedInfo, gSyscallFilterList, sizeof(gSyscallFilterList), NULL);
69 |
70 | gFilterListInit = TRUE;
71 | }
72 |
73 | WDBG_PTR pProcess = GetExpression("$proc");
74 | GetFieldOffset("nt!_EPROCESS", "Win32KFilterSet", &Offset);
75 | ReadMemory(pProcess + Offset, &FilterSet, sizeof(FilterSet), NULL);
76 | dprintf("current proc filter set: %d\n", FilterSet);
77 | if (FilterSet < 0 && FilterSet > 6) {
78 | dprintf("level in [0-6]\n");
79 | return S_OK;
80 | }
81 | //iLevel = FilterSet;
82 |
83 |
84 | if (!gSyscallFilterList[FilterSet].nCounts || !gSyscallFilterList[FilterSet].lpFuncName){
85 | dprintf("no filter\n");
86 | return S_OK;
87 | }
88 |
89 |
90 | dprintf("allow list:\n");
91 | for (int i = 0; i < gSyscallFilterList[FilterSet].nCounts; i++) {
92 | std::string strRead;
93 |
94 | //
95 | // read the string pointer
96 | //
97 |
98 | ULONG_PTR pFuncNameAddr = (ULONG_PTR)gSyscallFilterList[FilterSet].lpFuncName + i * sizeof(ULONG_PTR);
99 | ULONG_PTR pFuncName;
100 | if (!ReadMemory(pFuncNameAddr, (PVOID)&pFuncName, sizeof(pFuncName), NULL)) {
101 | break;
102 | }
103 |
104 | //
105 | // read the function name
106 | //
107 |
108 | if (!ReadString((WDBG_PTR)pFuncName, strRead)){
109 | break;
110 | }
111 | dprintf("\t\t%s\n", strRead.c_str());
112 | }
113 |
114 | return S_OK;
115 | }
--------------------------------------------------------------------------------
/gdiexts.cxx:
--------------------------------------------------------------------------------
1 |
2 | #include "stdafx.h"
3 | #include "object/region.hpp"
4 | #include "object/suface.hpp"
5 | #include "object/palette.hpp"
6 |
7 | VOID Gdidr(
8 | REGION * prgn
9 | );
10 |
11 | VOID Gdicr(
12 | REGION * prgn
13 | );
14 |
15 | VOID Gdidppal(
16 | PALETTE * pvServer
17 | );
18 |
19 | VOID Gdidpsurf(
20 | PVOID pvServer
21 | );
22 |
23 | #define DbgPrint
24 |
25 | /**************************************************************************\
26 | *
27 | * move(dst, src ptr)
28 | *
29 | \**************************************************************************/
30 |
31 | #define move(dst, src) \
32 | ReadMemory((ULONG_PTR)(src), &(dst), sizeof(dst), NULL);
33 |
34 | /**************************************************************************\
35 | *
36 | * move2(dst ptr, src ptr, num bytes)
37 | *
38 | \**************************************************************************/
39 | #define move2(dst, src, size) \
40 | ReadMemory((ULONG_PTR) (src), &(dst), (size), NULL);
41 |
42 |
43 | EXTERN_C
44 | HRESULT CALLBACK
45 | dr(PDEBUG_CLIENT4 Client, PCSTR args)
46 | {
47 | /*ULONG prgn;
48 |
49 | if (*args != '\0')
50 | sscanf(args, "%lx", &prgn);
51 | else
52 | {
53 | dprintf("Please supply an argument \n");
54 | return;
55 | }*/
56 |
57 | ULONG_PTR prgn;
58 | prgn = GetExpression(args);
59 | if (!prgn){
60 | dprintf("Please supply an argument \n");
61 | return S_OK;
62 | }
63 |
64 | Gdidr((REGION *)prgn);
65 | return S_OK;
66 | }
67 |
68 |
69 | /******************************Public*Routine******************************\
70 | * VOID Gdidr (
71 | * PVOID prgn
72 | * )
73 | *
74 | * Debugger extension to dump a region.
75 | *
76 | * History:
77 | * 14-Feb-1992 -by- Mike Harrington [Mikehar]
78 | * Wrote it.
79 | \**************************************************************************/
80 |
81 | VOID Gdidr(
82 | REGION * prgn
83 | )
84 | {
85 | REGION rgn;
86 | PSCAN pscnHead;
87 | //ULONG i;
88 | BOOL bCheck = FALSE;
89 |
90 | move(rgn, prgn);
91 | //pscnHead = (PSCAN)((PBYTE)prgn + sizeof(rgn));
92 | pscnHead = (PSCAN)((PBYTE)prgn + offsetof(REGION, scan));
93 |
94 | dprintf(
95 | "hHmgr 0x%p\n"
96 | "cExLock 0x%p\n"
97 | "tid 0x%p\n"
98 | "sizeObj 0x%lx\n"
99 | "sizeRgn 0x%lx\n"
100 | "cRefs %ld\n"
101 | "cScans %ld\n"
102 | "rcl {0x%lx 0x%lx 0x%lx 0x%lx}\n"
103 | "pscnHead 0x%p\n"
104 | "pscnTail 0x%p\n",
105 |
106 | rgn.hHmgr,
107 | rgn.cExclusiveLock,
108 | rgn.Tid,
109 | rgn.sizeObj,
110 | rgn.sizeRgn,
111 | rgn.cRefs,
112 | rgn.cScans,
113 | rgn.rcl.left, rgn.rcl.top, rgn.rcl.right, rgn.rcl.bottom,
114 | pscnHead,
115 | rgn.pscnTail);
116 |
117 | /*
118 | * make the region data accessible.
119 | */
120 |
121 | /*
122 | i = 0;
123 |
124 | {
125 | PSCAN pscn = (PSCAN)(prgn + 1);
126 | ULONG cscn = rgn.cScans;
127 |
128 | LONG lPrevBottom = NEG_INFINITY;
129 | LONG lPrevRight;
130 |
131 | while (cscn--)
132 | {
133 | LONG yTop;
134 | LONG yBottom;
135 | LONG cWalls;
136 | LONG cWalls2;
137 | LONG left;
138 | LONG right;
139 | ULONG iWall = 0;
140 |
141 | move(yTop, (PBYTE)pscn + offsetof(SCAN, yTop));
142 | move(yBottom, (PBYTE)pscn + offsetof(SCAN, yBottom));
143 | move(cWalls, (PBYTE)pscn + offsetof(SCAN, cWalls));
144 |
145 | if (bCheck){
146 | if (yTop < lPrevBottom)
147 | {
148 | dprintf("top < prev bottom, scan %ld, pscn @ 0x%lx\n",
149 | rgn.cScans - cscn, (BYTE *)pscn - (BYTE *)prgn);
150 | return;
151 | }
152 |
153 | if (yTop > yBottom)
154 | {
155 | dprintf("top > bottom, scan %ld, pscn @ 0x%lx\n",
156 | rgn.cScans - cscn, (BYTE *)pscn - (BYTE *)prgn);
157 | return;
158 | }
159 | }
160 |
161 |
162 | lPrevBottom = yBottom;
163 | lPrevRight = NEG_INFINITY;
164 |
165 | while ((LONG)iWall < cWalls)
166 | {
167 | move(left, (PBYTE)pscn + offsetof(SCAN, ai_x[iWall]));
168 | move(right, (PBYTE)pscn + offsetof(SCAN, ai_x[iWall + 1]));
169 |
170 | if (bCheck) {
171 | if ((left <= lPrevRight) || (right <= left))
172 | {
173 | dprintf("left[i] < left[i+1], pscn @ 0x%lx, iWall = 0x%lx\n",
174 | (BYTE *)pscn - (BYTE *)prgn, iWall);
175 | return;
176 | }
177 | }
178 |
179 | lPrevRight = right;
180 |
181 | dprintf("\tRectangle #%d { 0x%lx, 0x%lx, 0x%lx, 0x%lx }\n",
182 | i, left, yTop, right, yBottom);
183 |
184 | ++i;
185 |
186 | iWall += 2;
187 |
188 | if (CheckControlC())
189 | return;
190 | }
191 |
192 | move(cWalls2, (PBYTE)pscn + offsetof(SCAN, ai_x[iWall]));
193 |
194 | if (bCheck) {
195 | if (cWalls != cWalls2)
196 | {
197 | dprintf("cWalls != cWalls2 @ 0x%lx\n",
198 | (BYTE *)pscn - (BYTE *)prgn);
199 | return;
200 | }
201 | }
202 |
203 | pscn = (PSCAN)((PBYTE)pscn + (cWalls * sizeof(LONG) + sizeof(SCAN)));
204 |
205 | if ((ULONG_PTR)pscn >= (ULONG_PTR)rgn.pscnTail)
206 | {
207 | //dprintf("Went past end of region\n");
208 | return;
209 | }
210 | }
211 | }*/
212 |
213 | ULONG cScans = rgn.cScans;
214 | PSCAN pscn = pscnHead;
215 |
216 | if (cScans){
217 | dprintf("------------dump cScan------------\n");
218 | }
219 |
220 | for (ULONG i = 0;
221 | i < cScans;
222 | i++)
223 | {
224 | ULONG cWalls;
225 | LONG yTop;
226 | LONG yBottom;
227 | LONG left;
228 | LONG right;
229 |
230 | move(yTop, (PBYTE)pscn + offsetof(SCAN, yTop));
231 | move(yBottom, (PBYTE)pscn + offsetof(SCAN, yBottom));
232 | move(cWalls, (PBYTE)pscn + offsetof(SCAN, cWalls));
233 |
234 |
235 | if (!cWalls){
236 | dprintf("\tScan #%d: yTop = 0x%lx, yBottom = 0x%lx, cWalls = %ld\n",
237 | i, yTop, yBottom, cWalls);
238 | }else{
239 | for (ULONG j = 0;
240 | j < cWalls;
241 | j += 2)
242 | {
243 | move(left, (PBYTE)pscn + offsetof(SCAN, ai_x[j]));
244 | move(right, (PBYTE)pscn + offsetof(SCAN, ai_x[j + 1]));
245 |
246 | dprintf("\tScan #%d: { 0x%lx, 0x%lx, 0x%lx, 0x%lx }\n",
247 | i, left, yTop, right, yBottom);
248 | }
249 | }
250 |
251 | //pscn = pscnGet(pscn);
252 | pscn = (PSCAN)((PBYTE)pscn + (cWalls * sizeof(LONG) + sizeof(SCAN)));
253 | }
254 | }
255 |
256 |
257 | EXTERN_C
258 | HRESULT CALLBACK
259 | cr(PDEBUG_CLIENT4 Client, PCSTR args)
260 | {
261 | ULONG_PTR prgn;
262 | prgn = GetExpression(args);
263 | if (!prgn) {
264 | dprintf("Please supply an argument \n");
265 | return S_OK;
266 | }
267 |
268 | Gdicr((REGION *)prgn);
269 | return S_OK;
270 | }
271 |
272 |
273 | VOID Gdicr(
274 | REGION * prgn
275 | )
276 | {
277 | REGION rgn;
278 | PSCAN pscnHead;
279 | BOOL bCheck = TRUE;
280 |
281 | move(rgn, prgn);
282 | pscnHead = (PSCAN)((PBYTE)prgn + sizeof(rgn));
283 |
284 | dprintf("pr = %lx, sizeof(rgn) = %lx, pscnHead = %lx\n", prgn, sizeof(rgn), pscnHead);
285 |
286 | dprintf(
287 | "hHmgr 0x%p\n"
288 | "cExLock 0x%p\n"
289 | "tid 0x%p\n"
290 | "sizeObj 0x%lx\n"
291 | "sizeRgn 0x%lx\n"
292 | "cRefs %ld\n"
293 | "cScans %ld\n"
294 | "rcl {0x%lx 0x%lx 0x%lx 0x%lx}\n"
295 | "pscnHead 0x%p\n"
296 | "pscnTail 0x%p\n",
297 |
298 | rgn.hHmgr,
299 | rgn.cExclusiveLock,
300 | rgn.Tid,
301 | rgn.sizeObj,
302 | rgn.sizeRgn,
303 | rgn.cRefs,
304 | rgn.cScans,
305 | rgn.rcl.left, rgn.rcl.top, rgn.rcl.right, rgn.rcl.bottom,
306 | pscnHead,
307 | rgn.pscnTail);
308 |
309 | if ((pscnHead > rgn.pscnTail) ||
310 | (rgn.sizeObj < rgn.sizeRgn))
311 | {
312 | DbgPrint("Error in region\n");
313 | return;
314 | }
315 |
316 | /*
317 | * make the region data accessable.
318 | */
319 |
320 | {
321 | PSCAN pscn = (PSCAN)((REGION *)prgn + 1);
322 | ULONG cscn = rgn.cScans;
323 |
324 | LONG lPrevBottom = NEG_INFINITY;
325 | LONG lPrevRight;
326 |
327 | while (cscn--)
328 | {
329 | LONG yTop;
330 | LONG yBottom;
331 | LONG cWalls;
332 | LONG cWalls2;
333 | LONG left;
334 | LONG right;
335 | ULONG iWall = 0;
336 |
337 | move(yTop, (PBYTE)pscn + offsetof(SCAN, yTop));
338 | move(yBottom, (PBYTE)pscn + offsetof(SCAN, yBottom));
339 | move(cWalls, (PBYTE)pscn + offsetof(SCAN, cWalls));
340 |
341 | if (yTop < lPrevBottom)
342 | {
343 | dprintf("top(0x%lx) < prev bottom(0x%lx), scan %ld, pscn @ 0x%lx\n",
344 | yTop, lPrevBottom, rgn.cScans - cscn, (BYTE *)pscn - (BYTE *)prgn);
345 | bCheck = FALSE;
346 | break;
347 | }
348 |
349 | if (yTop > yBottom)
350 | {
351 | dprintf("top(0x%lx) > bottom(0x%lx), scan %ld, pscn @ 0x%lx\n",
352 | yTop, yBottom, rgn.cScans - cscn, (BYTE *)pscn - (BYTE *)prgn);
353 | bCheck = FALSE;
354 | break;
355 | }
356 |
357 | lPrevBottom = yBottom;
358 | lPrevRight = NEG_INFINITY;
359 |
360 | while ((LONG)iWall < cWalls)
361 | {
362 | move(left, (PBYTE)pscn + offsetof(SCAN, ai_x[iWall]));
363 | move(right, (PBYTE)pscn + offsetof(SCAN, ai_x[iWall + 1]));
364 |
365 | if ((left <= lPrevRight) || (right <= left))
366 | {
367 | dprintf("left[i] < left[i+1], pscn @ 0x%lx, iWall = 0x%lx\n",
368 | (BYTE *)pscn - (BYTE *)prgn, iWall);
369 | bCheck = FALSE;
370 | break;
371 | }
372 |
373 | lPrevRight = right;
374 |
375 | iWall += 2;
376 |
377 | if (CheckControlC())
378 | return;
379 | }
380 | if (!bCheck){
381 | break;
382 | }
383 |
384 | move(cWalls2, (PBYTE)pscn + offsetof(SCAN, ai_x[iWall]));
385 |
386 | if (cWalls != cWalls2)
387 | {
388 | dprintf("cWalls != cWalls2 @ 0x%lx\n",
389 | (BYTE *)pscn - (BYTE *)prgn);
390 | bCheck = FALSE;
391 | break;
392 | }
393 |
394 | pscn = (PSCAN)((PBYTE)pscn + (cWalls * sizeof(LONG) + sizeof(SCAN)));
395 |
396 | if ((ULONG_PTR)pscn >= (ULONG_PTR)rgn.pscnTail)
397 | {
398 | //dprintf("Went past end of region\n");
399 | break;
400 | }
401 | }
402 | }
403 |
404 | if (!bCheck){
405 | dprintf("region check failed\n");
406 | }else{
407 | dprintf("region check success\n");
408 | }
409 |
410 | }
411 |
412 | PSZ gapszBMF[] =
413 | {
414 | "BMF_ERROR",
415 | "BMF_1BPP",
416 | "BMF_4BPP",
417 | "BMF_8BPP",
418 | "BMF_16BPP",
419 | "BMF_24BPP",
420 | "BMF_32BPP",
421 | "BMF_4RLE",
422 | "BMF_8RLE"
423 | };
424 |
425 | PSZ gapszSTYPE[] =
426 | {
427 | "STYPE_BITMAP",
428 | "STYPE_DEVICE",
429 | "Unused",
430 | "STYPE_DEVBITMAP",
431 | };
432 |
433 | ULONG ulSizeSURFACE()
434 | {
435 | ULONG surfSize;
436 | move(surfSize, GetExpression("win32kbase!SURFACE::tSize"));
437 | if (surfSize != sizeof(SURFACE)){
438 | DEBUGPRINT("!!!WARNING!!!surface struct has been changed(our=(0x%x, system=0x%x) please check it." \
439 | "and the information may be wrong\n",
440 | sizeof(SURFACE), surfSize);
441 | }
442 | return sizeof(SURFACE);
443 | }
444 |
445 | VOID vPrintSURFACE(PVOID pv)
446 | {
447 | SURFACE *pso = (SURFACE *)pv;
448 |
449 | //
450 | // SURFACE structure
451 | //
452 |
453 | dprintf("--------------------------------------------------\n");
454 | dprintf("DHSURF dhsurf 0x%p\n", pso->so.dhsurf);
455 | dprintf("HSURF hsurf 0x%p\n", pso->so.hsurf);
456 | dprintf("DHPDEV dhpdev 0x%p\n", pso->so.dhpdev);
457 | dprintf("HDEV hdev 0x%p\n", pso->so.hdev);
458 | dprintf("SIZEL sizlBitmap.cx 0x%lx\n", pso->so.sizlBitmap.cx);
459 | dprintf("SIZEL sizlBitmap.cy 0x%lx\n", pso->so.sizlBitmap.cy);
460 | dprintf("ULONG cjBits 0x%lx\n", pso->so.cjBits);
461 | dprintf("PVOID pvBits 0x%p\n", pso->so.pvBits);
462 | dprintf("PVOID pvScan0 0x%p\n", pso->so.pvScan0);
463 | dprintf("LONG lDelta 0x%lx\n", pso->so.lDelta);
464 | dprintf("ULONG iUniq 0x%lx\n", pso->so.iUniq);
465 | dprintf("ULONG iBitmapFormat 0x%lx, %s\n", pso->so.iBitmapFormat,
466 | pso->so.iBitmapFormat > BMF_8RLE ? "ERROR" : gapszBMF[pso->so.iBitmapFormat]);
467 |
468 | #if 0
469 | if (pso->DIB.hDIBSection)
470 | {
471 | dprintf("USHORT iType DIBSECTION\n");
472 |
473 | dprintf("HANDLE hDIBSection 0x%lx\n", pso->DIB.hDIBSection);
474 | dprintf("HANDLE hSecure 0x%lx\n", pso->DIB.hSecure);
475 | dprintf("DWORD dwOffset 0x%lx\n", pso->DIB.dwOffset);
476 | }else{
477 | dprintf("USHORT iType 0x%x, %s\n", pso->so.iType,
478 | pso->so.iType > STYPE_DEVBITMAP ? "ERROR" : gapszSTYPE[pso->so.iType]);
479 | }
480 | #endif
481 |
482 | dprintf("USHORT iType 0x%x, %s\n", pso->so.iType,
483 | pso->so.iType > STYPE_DEVBITMAP ? "ERROR" : gapszSTYPE[pso->so.iType]);
484 |
485 |
486 | dprintf("USHORT fjBitmap 0x%x\n", pso->so.fjBitmap);
487 |
488 | #if 0
489 | dprintf("XDCOBJ* pdcoAA 0x%ln\n", pso->pdcoAA);
490 | dprintf("FLONG flags 0x%lx\n", pso->SurfFlags);
491 | #endif
492 | dprintf("PPALETTE ppal 0x%p\n", pso->pPal);
493 |
494 | #if 0
495 | dprintf("PFN_DrvBitBlt pfnBitBlt 0x%lx\n", pso->pFnBitBlt);
496 | dprintf("PFN_DrvTextOut pfnTextOut 0x%lx\n", pso->pFnTextOut);
497 | #endif
498 |
499 | #if 0
500 | if ((pso->so.iType == STYPE_BITMAP) ||
501 | (pso->so.iType == STYPE_DEVBITMAP)){
502 |
503 | dprintf("HDC hdc 0x%lx\n", pso->EBitmap.hdc);
504 | dprintf("ULONG cRef 0x%lx\n", pso->EBitmap.cRef);
505 | dprintf("HPALETTE hpalHint 0x%lx\n", pso->EBitmap.hpalHint);
506 | }
507 |
508 | if (pso->flags & PDEV_SURFACE)
509 | {
510 | dprintf("This is the enabled surface for a PDEV\n");
511 | }
512 |
513 | #endif
514 |
515 | dprintf("--------------------------------------------------\n");
516 | }
517 |
518 | VOID Gdidpsurf(
519 | PVOID pvServer)
520 | {
521 | char pso[1024];
522 |
523 | move2(pso, pvServer, ulSizeSURFACE());
524 |
525 | dprintf("SURFACE structure at 0x%p:\n", pvServer);
526 | vPrintSURFACE((PVOID)pso);
527 | }
528 |
529 |
530 | EXTERN_C
531 | HRESULT CALLBACK
532 | dpsurf(PDEBUG_CLIENT4 Client, PCSTR args)
533 | {
534 | ULONG_PTR psurf;
535 | psurf = GetExpression(args);
536 | if (!psurf) {
537 | dprintf("Please supply an argument \n");
538 | return S_OK;
539 | }
540 |
541 | Gdidpsurf((PVOID *)psurf);
542 | return S_OK;
543 | }
544 |
545 | VOID Gdidpso(
546 | PVOID pvServer)
547 | {
548 | char pso[1024];
549 |
550 | //
551 | // subtract offset of BASE OBJECT FROM SURFOBJ
552 | //
553 |
554 | pvServer = (PVOID)((PUCHAR)pvServer - /*sizeof(BASEOBJECT)*/0x18);
555 |
556 | move2(pso, pvServer, ulSizeSURFACE());
557 |
558 | dprintf("SURFACE structure at 0x%p:\n", pvServer);
559 | vPrintSURFACE((PVOID)pso);
560 | }
561 |
562 |
563 | EXTERN_C
564 | HRESULT CALLBACK
565 | dpso(PDEBUG_CLIENT4 Client, PCSTR args)
566 | {
567 | ULONG_PTR pso;
568 | pso = GetExpression(args);
569 | if (!pso) {
570 | dprintf("Please supply an argument \n");
571 | return S_OK;
572 | }
573 |
574 | Gdidpso((PVOID *)pso);
575 | return S_OK;
576 | }
577 |
578 |
579 | ULONG ulSizePALETTE()
580 | {
581 | return((ULONG) sizeof(PALETTE));
582 | }
583 |
584 | VOID
585 | vPrintPALETTE(
586 | PALETTE * pvServer
587 | )
588 | {
589 | PALETTE *ppal;
590 | char pso[1024];
591 |
592 | move2(pso, pvServer, ulSizePALETTE());
593 |
594 | dprintf("EPALOBJ structure at 0x%p:\n", pvServer);
595 |
596 | ppal = (PALETTE *)pso;
597 |
598 | dprintf("--------------------------------------------------\n");
599 | dprintf("FLONG flPal 0x%lx\n", ppal->flPal);
600 | dprintf("ULONG cEntries 0x%lx\n", ppal->cEntries);
601 | dprintf("ULONG ulTime 0x%lx\n", ppal->ulTime);
602 | dprintf("HDC hdcHead 0x%p\n", ppal->hdcHead);
603 | dprintf("HDEVPPAL hSelected 0x%p\n", ppal->hSelected.hdev);
604 | dprintf("ULONG cRefhpal 0x%lx\n", ppal->cRefhpal);
605 | dprintf("ULONG cRefRegular 0x%lx\n", ppal->cRefRegular);
606 | dprintf("PTRANSLATE ptransFore 0x%p\n", ppal->ptransFore);
607 | dprintf("PTRANSLATE ptransCurrent 0x%p\n", ppal->ptransCurrent);
608 | dprintf("PTRANSLATE ptransOld 0x%p\n", ppal->ptransOld);
609 |
610 | // For DirectDraw surfaces, sometimes the colour table is shared
611 | // with another palette:
612 |
613 | if (ppal->ppalColor != ppal)
614 | {
615 | dprintf("PPALETTE ppalColor 0x%p\n", ppal->ppalColor);
616 | }
617 |
618 | dprintf("PAL_ULONG apalColor 0x%p\n", ppal->apalColor);
619 | dprintf("--------------------------------------------------\n");
620 | }
621 |
622 |
623 | EXTERN_C
624 | HRESULT CALLBACK
625 | dppal(PDEBUG_CLIENT4 Client, PCSTR args)
626 | {
627 | PALETTE* ppal;
628 | ppal = (PALETTE*)GetExpression(args);
629 | if (!ppal) {
630 | dprintf("Please supply an argument \n");
631 | return S_OK;
632 | }
633 |
634 | Gdidppal(ppal);
635 | return S_OK;
636 | }
637 |
638 | void Gdidppal(
639 | PALETTE * pvServer)
640 | {
641 | vPrintPALETTE(pvServer);
642 | }
--------------------------------------------------------------------------------
/handle.cxx:
--------------------------------------------------------------------------------
1 |
2 | #include "stdafx.h"
3 | #include "dbgext.hpp"
4 | #include "handle.hpp"
5 |
6 | #include "utils.hpp"
7 | #include "SimpleOpt.h"
8 |
9 |
10 | typedef struct _TYPE_DESC
11 | {
12 | int Type;
13 | LPCSTR lpszTypeDesc;
14 | }TYPE_DESC, *PTYPE_DESC;
15 |
16 | TYPE_DESC gGdiTypeDesc[] =
17 | {
18 | { 0x01, "DC" },
19 | { 0x02, "ColorTransform" },
20 | { 0x04, "Rgn" },
21 | { 0x05, "Bitmap" },
22 | { 0x07, "Path" },
23 | { 0x08, "Palette" },
24 | { 0x09, "ColorSpace" },
25 | { 0x0a, "Font" },
26 | { 0x0e, "ColorTransform" },
27 | { 0x0f, "Sprite" },
28 | { 0x10, "Brush" },
29 | { 0x12, "LogicSurface" },
30 | { 0x13, "Space" },
31 | { 0x15, "ServerMetafile" },
32 | { 0x1c, "Driver" },
33 | { 0x8a, "Font2" },
34 | };
35 |
36 | TYPE_DESC gUserTypeDesc[] =
37 | {
38 | { 0x01, "Window" }, //0x190
39 | { 0x02, "Menu" }, //0xb0
40 | { 0x03, "Cursor" }, //0x98
41 | { 0x04, "DeferWindowPos" }, //0x30
42 | { 0x05, "WindowHook" }, //0x60
43 | { 0x06, "MemoryHandle" },
44 | { 0x07, "CPD" }, //0x48
45 | { 0x08, "AcceleratorTable" },
46 | { 0x09, "CsDde" }, //0x40
47 | { 0x0a, "Conversation" }, //0x60
48 | { 0x0b, "pxs" }, //0x48
49 | { 0x0c, "Monitor" }, //0x260
50 | { 0x0d, "Keyboard" }, //0x78
51 | { 0x0e, "KeyboardLayout" }, //0x78
52 | { 0x0f, "EventHook" }, //0x60
53 | { 0x10, "Timer" }, //0x88
54 | { 0x11, "InputContext" }, //0x48
55 | { 0x12, "HidData" },
56 | { 0x14, "TouchInputInfo" },
57 | { 0x15, "GestureInfo" },
58 | { 0x17, "BaseWindow" } //0x80
59 | };
60 |
61 |
62 | #define HMINDEXBITS 0x0000FFFF // bits where index is stored
63 | #define HMUNIQSHIFT 16 // bits to shift uniqueness
64 | #define HMUNIQBITS 0xFFFF // valid uniqueness bits
65 | #define HMIndexFromHandle(h) (((DWORD)h) & HMINDEXBITS)
66 | #define HMUniqFromHandle(h) ((WORD)((((DWORD)h) >> HMUNIQSHIFT) & HMUNIQBITS))
67 |
68 | #define OCF_THREADOWNED 0x0001
69 | #define OCF_PROCESSOWNED 0x0002
70 | #define OCF_MARKTHREAD 0x0004
71 | #define OCF_USEQUOTA 0x0008
72 |
73 | const LPCSTR gTypeUnknonw = "Unknown";
74 |
75 | LPCSTR
76 | GetUserTypeDesc(
77 | IN UCHAR Type
78 | )
79 | {
80 | LPCSTR lpTypeDesc = gTypeUnknonw;
81 | for (int i = 0; i < _countof(gUserTypeDesc); i++) {
82 | if (gUserTypeDesc[i].Type == Type) {
83 | lpTypeDesc = gUserTypeDesc[i].lpszTypeDesc;
84 | break;
85 | }
86 | }
87 | return lpTypeDesc;
88 | }
89 |
90 | BOOL
91 | IsUserTypeValid(
92 | IN UCHAR Type
93 | )
94 | {
95 | for (int i = 0; i < _countof(gGdiTypeDesc); i++) {
96 | if (gUserTypeDesc[i].Type == Type) {
97 | return TRUE;
98 | }
99 | }
100 | return FALSE;
101 | }
102 |
103 | BOOL
104 | UserObjectGetEntry(
105 | IN UINT32 Index,
106 | OUT PHANDLEENTRY pphe,
107 | OUT PKERNEL_HANDLEENTRY pKrlEntry,
108 | OPTIONAL OUT PUSER_TYPE_DESC pCreateInfo
109 | );
110 |
111 | EXTERN_C
112 | HRESULT
113 | CALLBACK
114 | uh(PDEBUG_CLIENT4 Client, PCSTR args)
115 | {
116 | ULONG64 hUser;
117 | hUser = GetExpression(args);
118 |
119 | ULONG Index = HMIndexFromHandle(hUser);
120 | WORD wUniq = HMUniqFromHandle(hUser);
121 |
122 | HANDLEENTRY HandleEntry;
123 | KERNEL_HANDLEENTRY KernelHandleEntry;
124 | USER_TYPE_DESC CreateInfo;
125 |
126 | INIT_API();
127 |
128 | do
129 | {
130 | BOOL bRet = UserObjectGetEntry(Index, &HandleEntry, &KernelHandleEntry, &CreateInfo);
131 | if (!bRet){
132 | break;
133 | }
134 |
135 | if (KernelHandleEntry.pOwner) {
136 |
137 | ULONG_PTR Handle;
138 | LPCSTR lpszOwnerType = "Unknown";
139 | ULONG_PTR pObject = NULL;
140 |
141 | //
142 | // read the handle from object
143 | // the user object always start with "HEAD"
144 | //
145 |
146 | if (!ReadPointer((ULONG64)KernelHandleEntry.pObject, &Handle)) {
147 | dprintf("can not handle at 0x%p\n", KernelHandleEntry.pObject);
148 | break;
149 | }
150 |
151 | if (CreateInfo.CreateFlag & OCF_PROCESSOWNED) {
152 |
153 | //
154 | // the owner is PROCESSINFO
155 | // W32PROCESS
156 | //
157 |
158 | lpszOwnerType = "Process";
159 |
160 | if (!ReadPointer((ULONG64)KernelHandleEntry.pOwner, &pObject)) {
161 | dprintf("can not handle at 0x%p\n", KernelHandleEntry.pOwner);
162 | break;
163 | }
164 |
165 | }else if (CreateInfo.CreateFlag & OCF_THREADOWNED) {
166 |
167 | //
168 | // The Owner is THREADINFO
169 | // W32THREAD
170 | //
171 |
172 | ULONG_PTR pWin32Thread;
173 | lpszOwnerType = "Thread";
174 |
175 | if (!ReadPointer((ULONG64)KernelHandleEntry.pOwner, &pWin32Thread)) {
176 | dprintf("can not handle at 0x%p\n", KernelHandleEntry.pOwner);
177 | break;
178 | }
179 |
180 | //
181 | // So here is _ETHREAD
182 | //
183 |
184 | if (GetFieldValue(pWin32Thread, "nt!_KTHREAD", "Process", pObject)) {
185 | dprintf("can not process at thread 0x%p\n", pWin32Thread);
186 | break;
187 | }
188 | }else{
189 |
190 | }
191 |
192 | ExtOutDml(
193 | "Object Handle 0x%llx\n"
194 | "Object Type %s(%d)\n"
195 | "Create Flag 0x%x\n"
196 | "Object 0x%p\n"
197 | "pOwner 0x%p\n"
198 | "process 0x%p\n",
199 | hUser,
200 | GetUserTypeDesc(HandleEntry.Type), (ULONG)HandleEntry.Type,
201 | CreateInfo.CreateFlag,
202 | KernelHandleEntry.pObject,
203 | KernelHandleEntry.pOwner,
204 | pObject, pObject
205 | );
206 | }
207 | } while (FALSE);
208 |
209 | EXIT_API();
210 |
211 | return S_OK;
212 | }
213 |
214 | LPCSTR
215 | GetGdiTypeDesc(
216 | IN UCHAR Type
217 | )
218 | {
219 | LPCSTR lpTypeDesc = gTypeUnknonw;
220 | for (int i = 0; i < _countof(gGdiTypeDesc); i++) {
221 | if (gGdiTypeDesc[i].Type == Type) {
222 | lpTypeDesc = gGdiTypeDesc[i].lpszTypeDesc;
223 | break;
224 | }
225 | }
226 | return lpTypeDesc;
227 | }
228 |
229 | BOOL
230 | IsGdiTypeValid(
231 | IN UCHAR Type
232 | )
233 | {
234 | for (int i = 0; i < _countof(gGdiTypeDesc); i++) {
235 | if (gGdiTypeDesc[i].Type == Type) {
236 | return TRUE;
237 | }
238 | }
239 | return FALSE;
240 | }
241 |
242 | BOOL
243 | DirectoryGetEntry(
244 | IN UINT32 Index,
245 | OUT PVOID* ppEntry,
246 | OUT PVOID* pLookupEntry
247 | )
248 | {
249 | ULONG uReturn;
250 | BOOL bRet;
251 |
252 | HANDLEMGR HandleMgr;
253 | WDBG_PTR kHandleMgr = GetExpression("poi(win32kbase!gpHandleManager)");
254 |
255 | if (ppEntry) {
256 | *ppEntry = NULL;
257 | }
258 |
259 | if (pLookupEntry) {
260 | *pLookupEntry = NULL;
261 | }
262 |
263 | //
264 | // get entire handle mgr
265 | //
266 |
267 | bRet = ReadMemory(kHandleMgr, &HandleMgr, sizeof(HandleMgr), &uReturn);
268 | if (!bRet) {
269 | dprintf("can not read win32kbase!gpHandleManager at %p\n", kHandleMgr);
270 | return FALSE;
271 | }
272 |
273 | if (HandleMgr.TotalGdiHandleCounts <= 0x10000){
274 | Index = (USHORT)Index;
275 | }
276 |
277 | //
278 | // read handle directory
279 | //
280 |
281 | HANDLEENTRYDIR HandleDir;
282 | bRet = ReadMemory((WDBG_PTR)(ULONG_PTR)(HandleMgr.pHandleEntryDir), &HandleDir, sizeof(HandleDir), &uReturn);
283 | if (!bRet) {
284 | dprintf("can not read handle directory at %p\n", HandleMgr.pHandleEntryDir);
285 | return FALSE;
286 | }
287 |
288 |
289 | //
290 | // GdiHandleEntryDirectory::_RetrieveTableAndTableEntryIndex
291 | // calculate the directory index and handle index
292 | //
293 |
294 | ULONG MaxDirGdiHandleCount = HandleDir.MaxDirGdiHandleCount;
295 | if (Index > (MaxDirGdiHandleCount + (UINT32)((HandleDir.DirCounts - 1) << 16))) {
296 | return FALSE;
297 | }
298 |
299 | UINT32 EntryIndex = Index;
300 | UINT32 DirIndex = 0;
301 | if (Index >= MaxDirGdiHandleCount) {
302 | DirIndex = ((Index - MaxDirGdiHandleCount) >> 16) + 1;
303 | }
304 |
305 | //
306 | // Read EntryTable
307 | //
308 |
309 | PVOID pEntryTableAddr = (PVOID)HandleDir.pEntryTable[DirIndex];
310 | HANDLEENTRYTABLE HandleEntryTable;
311 | bRet = ReadMemory((WDBG_PTR)pEntryTableAddr, &HandleEntryTable, sizeof(HandleEntryTable), &uReturn);
312 | if (!bRet) {
313 | dprintf("can not read win32kbase!gpHandleManager at %p\n", kHandleMgr);
314 | return FALSE;
315 | }
316 |
317 | //
318 | // Calculate Index of EntryTable
319 | // Here dirIndex is less than ushort_max
320 | //
321 | // the meaning of the EntryIndex:
322 | //
323 | // +--------+--------+
324 | // | lookup | index |
325 | // +--------+--------+
326 | // 16 8 0
327 | //
328 |
329 | if (DirIndex) {
330 | EntryIndex = Index - MaxDirGdiHandleCount - ((DirIndex - 1) << 16);
331 | }
332 |
333 | //
334 | // Read lookup table
335 | //
336 |
337 | ENTRYDATALOOKUPTABLE EntryLookupTable;
338 | bRet = ReadMemory((WDBG_PTR)HandleEntryTable.pEntryDataLookupTable, &EntryLookupTable, sizeof(EntryLookupTable), &uReturn);
339 | if (!bRet) {
340 | dprintf("can not read pEntryDataLookupTable at %p\n", HandleEntryTable.pEntryDataLookupTable);
341 | return FALSE;
342 | }
343 |
344 | //
345 | // Read lookup table entry
346 | //
347 |
348 | PLOOKUP_ENTRY pLookEntris;
349 | bRet = ReadMemory((WDBG_PTR)& EntryLookupTable.ppLookupEntries[EntryIndex >> 8],
350 | &pLookEntris, sizeof(pLookEntris), &uReturn);
351 | if (!bRet) {
352 | dprintf("can not read lookup Table Ptr at %p\n", EntryLookupTable.ppLookupEntries);
353 | return FALSE;
354 | }
355 |
356 | if (!pLookEntris){
357 | dprintf("lookup entry Table is null\n");
358 | return FALSE;
359 | }
360 |
361 | if (pLookupEntry) {
362 | *pLookupEntry = &pLookEntris[(UCHAR)EntryIndex];
363 | }
364 |
365 | //
366 | // read Handle Entry
367 | //
368 |
369 | if (ppEntry) {
370 | *ppEntry = &HandleEntryTable.pEntries[EntryIndex];
371 | }
372 |
373 | return TRUE;
374 |
375 | }
376 |
377 | EXTERN_C
378 | HRESULT
379 | CALLBACK
380 | gh(PDEBUG_CLIENT4 Client, PCSTR args)
381 | {
382 | ULONG uReturn;
383 | BOOL bRet;
384 |
385 | ULONG64 hGdi;
386 | hGdi = GetExpression(args) & 0xffffffff;
387 |
388 | //
389 | // first check the handle is valid
390 | //
391 |
392 | UCHAR Type = (hGdi >> 16) & 0xFF;
393 | ULONG Handle = (ULONG)hGdi;
394 |
395 | //
396 | // format handle. remove the type info and
397 | // move directory index
398 | //
399 |
400 | /*
401 | +--------+--------+--------+--------+
402 | | dir | type | lookup | index |
403 | +--------+--------+--------+--------+
404 | 32 24 16 8 0
405 | */
406 |
407 | Handle = (USHORT)Handle | ((Handle >> 8) & 0xFF0000);
408 |
409 | PVOID pEntry = NULL;
410 | PVOID pLookupEntry = NULL;
411 | if (DirectoryGetEntry(Handle, &pEntry, &pLookupEntry)) {
412 |
413 | //
414 | // Read the handle entry
415 | //
416 |
417 | ENTRY entry;
418 | LOOKUP_ENTRY LookupEntry;
419 |
420 | bRet = ReadMemory((WDBG_PTR)pLookupEntry, &LookupEntry, sizeof(LookupEntry), &uReturn);
421 | if (!bRet) {
422 | dprintf("can not read handle entry at %p\n", pEntry);
423 | return S_OK;
424 | }
425 |
426 | bRet = ReadMemory((WDBG_PTR)pEntry, &entry, sizeof(entry), &uReturn);
427 | if (!bRet) {
428 | dprintf("can not read handle entry at %p\n", pEntry);
429 | return S_OK;
430 | }
431 |
432 | if (entry.DirOrType != (USHORT)(hGdi >> 16)) {
433 | dprintf("!Handle Type mismatch please check it\n");
434 | }
435 |
436 | dprintf(
437 | "Object Type %s(%d)\n"
438 | "Handle 0x%llx\n"
439 | "Object 0x%p\n"
440 | "entry 0x%p\n"
441 | "processx 0x%x\n",
442 | GetGdiTypeDesc(Type), Type,
443 | hGdi,
444 | LookupEntry.pObject,
445 | pEntry, entry.ProcessIdOrSome
446 | );
447 | }else{
448 | dprintf("invalid handle value\n");
449 | }
450 | return S_OK;
451 | }
452 |
453 | ULONG
454 | GetTotalHandleCounts()
455 | {
456 | BOOL bRet;
457 | ULONG uReturn;
458 | HANDLEMGR HandleMgr;
459 | WDBG_PTR kHandleMgr = GetExpression("poi(win32kbase!gpHandleManager)");
460 |
461 |
462 | //
463 | // get entire handle mgr
464 | //
465 |
466 | bRet = ReadMemory(kHandleMgr, &HandleMgr, sizeof(HandleMgr), &uReturn);
467 | if (!bRet) {
468 | dprintf("can not read win32kbase!gpHandleManager at %p\n", kHandleMgr);
469 | return 0;
470 | }
471 |
472 | return HandleMgr.TotalGdiHandleCounts;
473 | }
474 |
475 | typedef struct _FILTER_CONTEXT
476 | {
477 | DWORD Flags;
478 | PVOID Process;
479 | int Type;
480 | }FILTER_CONTEXT, * PFILTER_CONTEXT;
481 |
482 | enum {
483 | OPT_HELP,
484 | OPT_FL_PROC = 1 << 0,
485 | OPT_FL_TYPE = 1 << 1
486 | };
487 | CSimpleOptA::SOption g_Options[] =
488 | {
489 | { OPT_HELP, "-h", SO_NONE },
490 | { OPT_HELP, "-?", SO_NONE },
491 | { OPT_HELP, "--help", SO_NONE },
492 | { OPT_FL_PROC, "-p", SO_REQ_SEP },
493 | { OPT_FL_TYPE, "-t", SO_REQ_SEP },
494 | SO_END_OF_OPTIONS
495 | };
496 |
497 | VOID
498 | ShowDumpGdiHandleHelp()
499 | {
500 | dprintf("Usage: !dgh [args]\n");
501 | dprintf("\n");
502 | dprintf("args list:\n");
503 | dprintf("-p [process] filter object by process\n");
504 | dprintf("-t [type id] filter object by type id\n");
505 | dprintf(" valid type:\n");
506 |
507 | LPCSTR lpTypeDesc = gTypeUnknonw;
508 | for (int i = 0; i < _countof(gGdiTypeDesc); i++) {
509 | dprintf(" id:%d - %s\n", gGdiTypeDesc[i].Type, gGdiTypeDesc[i].lpszTypeDesc);
510 | }
511 |
512 | dprintf("example:\n");
513 | dprintf("!dgh\n");
514 | dprintf(" will dump gdi object in system\n");
515 | dprintf("!dgh -p 0xffffffff13450080\n");
516 | dprintf(" will dump gdi object create by process 0xffffffff13450080\n");
517 | dprintf("!dgh -t 5\n");
518 | dprintf(" will dump all bitmap object\n");
519 | dprintf("!dgh -t 1 -p 0xffffffff13450080\n");
520 | dprintf(" will dump all bitmap object create by process 0xffffffff13450080\n");
521 | }
522 |
523 |
524 | BOOL
525 | DumpGdiHandle(
526 | IN PFILTER_CONTEXT Context
527 | )
528 | {
529 | /*
530 | +--------+--------+--------+--------+
531 | | dir | type | lookup | index |
532 | +--------+--------+--------+--------+
533 | 32 24 16 8 0
534 | */
535 |
536 | UINT32 TotalHandleCounts;
537 | UINT32 HandleV;
538 |
539 | //
540 | // Check type
541 | //
542 |
543 | if (Context->Flags & OPT_FL_TYPE) {
544 | if (!IsGdiTypeValid(Context->Type)) {
545 | dprintf("Invalid Gdi object type\n");
546 | return FALSE;
547 | }
548 | }
549 |
550 | TotalHandleCounts = GetTotalHandleCounts();
551 |
552 | if (!TotalHandleCounts) {
553 | dprintf("Have none gdi handle\n");
554 | return S_OK;
555 | }
556 |
557 | for (HandleV = 1; HandleV < TotalHandleCounts; HandleV++)
558 | {
559 |
560 | //
561 | // Get handle entry
562 | //
563 |
564 | PVOID pEntry = NULL;
565 | PVOID pLookupEntry = NULL;
566 | if (DirectoryGetEntry(HandleV, &pEntry, &pLookupEntry)) {
567 |
568 | //
569 | // Read the handle entry
570 | //
571 |
572 | BOOL bRet;
573 | ENTRY entry;
574 | LOOKUP_ENTRY LookupEntry;
575 | ULONG uReturn;
576 |
577 | bRet = ReadMemory((WDBG_PTR)pLookupEntry, &LookupEntry, sizeof(LookupEntry), &uReturn);
578 | if (!bRet) {
579 | dprintf("can not read handle entry at %p\n", pEntry);
580 | continue;
581 | }
582 |
583 | bRet = ReadMemory((WDBG_PTR)pEntry, &entry, sizeof(entry), &uReturn);
584 | if (!bRet) {
585 | dprintf("can not read handle entry at %p\n", pEntry);
586 | continue;
587 | }
588 |
589 |
590 | //
591 | // Is object exist?
592 | //
593 |
594 | if (LookupEntry.pObject) {
595 |
596 | //
597 | // combine handle
598 | //
599 |
600 | ULONG Handle;
601 |
602 | Handle = (ULONG)entry.DirOrType << 16 | (USHORT)HandleV;
603 |
604 | if ((Context->Flags & OPT_FL_TYPE && Context->Type != entry.Type)){
605 | continue;
606 | }
607 |
608 | dprintf("Handle:0x%08x Object=0x%p Type=%s(%d) entry=0x%p processx=0x%x\n",
609 | (ULONG64)Handle,
610 | LookupEntry.pObject,
611 | GetGdiTypeDesc(entry.Type), entry.Type,
612 | pEntry, entry.ProcessIdOrSome
613 | );
614 | }
615 | }
616 |
617 | if (CheckControlC() == TRUE) {
618 | dprintf("user control-c break\n");
619 | break;
620 | }
621 | }
622 |
623 | return TRUE;
624 | }
625 |
626 | EXTERN_C
627 | HRESULT
628 | CALLBACK
629 | dgh(PDEBUG_CLIENT4 Client, PCSTR args)
630 | {
631 | CStringA strCmds;
632 |
633 | int argc;
634 | PSTR* argv;
635 | FILTER_CONTEXT FilterContext = { 0 };
636 |
637 | strCmds.Format("!dgh %s", args);
638 | argv = CommandLineToArgvA(strCmds, &argc);
639 | CSimpleOptA Args(argc, argv, g_Options);
640 |
641 | while (Args.Next()) {
642 | if (Args.LastError() == SO_SUCCESS) {
643 | switch (Args.OptionId())
644 | {
645 | case OPT_FL_PROC:
646 | FilterContext.Flags |= OPT_FL_PROC;
647 | FilterContext.Process = (PVOID)strtoull(Args.OptionArg(), NULL, 16);
648 | dprintf("!!!!!filter by process not implement!!!!!!!!\n");
649 | break;
650 | case OPT_FL_TYPE:
651 | FilterContext.Flags |= OPT_FL_TYPE;
652 | FilterContext.Type = strtol(Args.OptionArg(), NULL, 10);
653 | break;
654 |
655 | case OPT_HELP:
656 | ShowDumpGdiHandleHelp();
657 | return S_OK;
658 | default:
659 | break;
660 | }
661 | }
662 | }
663 |
664 | INIT_API();
665 | DumpGdiHandle(&FilterContext);
666 | EXIT_API();
667 |
668 | return S_OK;
669 | }
670 |
671 |
672 | ULONG
673 | GetUserObjCounts()
674 | {
675 | ULONG uReturn;
676 | BOOL bRet;
677 |
678 | WDBG_PTR kgSharedInfo = GetExpression("win32kbase!gSharedInfo");
679 | SHAREDINFO SharedInfo;
680 | bRet = ReadMemory(kgSharedInfo, &SharedInfo, sizeof(SharedInfo), &uReturn);
681 | if (!bRet) {
682 | dprintf("can not read win32kbase!gSharedInfo at %p\n", kgSharedInfo);
683 | return 0;
684 | }
685 |
686 | //
687 | // read cHandleEntries from gpsi
688 | //
689 |
690 | ULONG_PTR cbHandleEntries = 0;
691 | bRet = ReadMemory((WDBG_PTR)SharedInfo.psi + sizeof(ULONG_PTR), &cbHandleEntries,
692 | sizeof(cbHandleEntries), &uReturn);
693 | if (!bRet) {
694 | dprintf("can not read gSharedInfo!cbHandleEntries at %p\n", (WDBG_PTR)SharedInfo.psi + sizeof(ULONG_PTR));
695 | return 0;
696 | }
697 |
698 | return (ULONG)cbHandleEntries;
699 | }
700 |
701 | BOOL
702 | UserObjectGetEntry(
703 | IN UINT32 Index,
704 | OUT PHANDLEENTRY pphe,
705 | OUT PKERNEL_HANDLEENTRY pKrlEntry,
706 | OPTIONAL OUT PUSER_TYPE_DESC pCreateInfo
707 | )
708 | {
709 | ULONG uReturn;
710 | BOOL bRet;
711 |
712 | if (!pphe || !pKrlEntry){
713 | return FALSE;
714 | }
715 |
716 | WDBG_PTR kpKernelHandleTable = GetExpression("win32kbase!gpKernelHandleTable");
717 | if (!kpKernelHandleTable) {
718 | dprintf("can not get symbol win32kbase!gpKernelHandleTable\n");
719 | return FALSE;
720 | }
721 | WDBG_PTR pKernelHandleTable;
722 | bRet = ReadMemory(kpKernelHandleTable, &pKernelHandleTable, sizeof(pKernelHandleTable), &uReturn);
723 | if (!bRet) {
724 | dprintf("can not read win32kbase!gpKernelHandleTable at %p\n", kpKernelHandleTable);
725 | return FALSE;
726 | }
727 |
728 |
729 | WDBG_PTR kgSharedInfo = GetExpression("win32kbase!gSharedInfo");
730 | SHAREDINFO SharedInfo;
731 | bRet = ReadMemory(kgSharedInfo, &SharedInfo, sizeof(SharedInfo), &uReturn);
732 | if (!bRet) {
733 | dprintf("can not read win32kbase!gpKernelHandleTable at %p\n", kpKernelHandleTable);
734 | return FALSE;
735 | }
736 |
737 | //
738 | // read cHandleEntries from gpsi
739 | //
740 |
741 | ULONG_PTR cbHandleEntries = 0;
742 | bRet = ReadMemory((WDBG_PTR)SharedInfo.psi + sizeof(ULONG_PTR), &cbHandleEntries,
743 | sizeof(cbHandleEntries), &uReturn);
744 | if (!bRet) {
745 | dprintf("can not read gSharedInfo!cbHandleEntries at %p\n", (WDBG_PTR)SharedInfo.psi + sizeof(ULONG_PTR));
746 | return FALSE;
747 | }
748 |
749 | //
750 | // check the handle
751 | //
752 |
753 | if (Index > cbHandleEntries) {
754 | dprintf("Invalid handle\n");
755 | return FALSE;
756 | }
757 |
758 | if (SharedInfo.aheSize != sizeof(HANDLEENTRY)) {
759 | dprintf("SharedInfo.aheSize != sizeof(HANDLEENTRY) please check\n");
760 | }
761 |
762 |
763 | //
764 | // read handle entry
765 | //
766 |
767 | bRet = ReadMemory((WDBG_PTR)SharedInfo.aheList + (ULONG_PTR)SharedInfo.aheSize * Index, pphe,
768 | sizeof(*pphe), &uReturn);
769 | if (!bRet) {
770 | dprintf("can not read phe at %p\n", (WDBG_PTR)SharedInfo.aheList + (ULONG_PTR)SharedInfo.aheSize * Index);
771 | return FALSE;
772 | }
773 |
774 | //
775 | // Check type
776 | //
777 |
778 | if (pphe->Type < 1){
779 | return FALSE;
780 | }
781 |
782 | //
783 | // get the real object
784 | //
785 |
786 | bRet = ReadMemory((WDBG_PTR)pKernelHandleTable + sizeof(KERNEL_HANDLEENTRY) * Index, pKrlEntry,
787 | sizeof(*pKrlEntry), &uReturn);
788 | if (!bRet) {
789 | dprintf("can not read kernel phe at %p\n", (WDBG_PTR)pKernelHandleTable + sizeof(KERNEL_HANDLEENTRY) * Index);
790 | return FALSE;
791 | }
792 |
793 | //
794 | // object createflag
795 | //
796 |
797 | if (pCreateInfo){
798 | WDBG_PTR kgahti = GetExpression("win32kbase!gahti");
799 | bRet = ReadMemory((WDBG_PTR)kgahti + sizeof(USER_TYPE_DESC) * pphe->Type, pCreateInfo,
800 | sizeof(*pCreateInfo), &uReturn);
801 | if (!bRet) {
802 | dprintf("can not read create info at %p\n", (WDBG_PTR)kgahti + sizeof(USER_TYPE_DESC) * pphe->Type);
803 | return FALSE;
804 | }
805 | }
806 |
807 |
808 | return TRUE;
809 | }
810 |
811 | VOID
812 | ShowDumpUserHandleHelp()
813 | {
814 | dprintf( "Usage: !duh [args]\n");
815 | dprintf("\n");
816 | dprintf("args list:\n");
817 | dprintf("-p [process] filter object by process\n");
818 | dprintf("-t [type id] filter object by type id\n");
819 | dprintf(" valid type:\n");
820 |
821 | LPCSTR lpTypeDesc = gTypeUnknonw;
822 | for (int i = 0; i < _countof(gUserTypeDesc); i++) {
823 | dprintf(" id:%d - %s\n", gUserTypeDesc[i].Type, gUserTypeDesc[i].lpszTypeDesc);
824 | }
825 |
826 | dprintf("example:\n");
827 | dprintf("!duh\n");
828 | dprintf(" will dump user object in system\n");
829 | dprintf("!duh -p 0xffffffff13450080\n");
830 | dprintf(" will dump user object create by process 0xffffffff13450080\n");
831 | dprintf("!duh -t 1\n");
832 | dprintf(" will dump all window object\n");
833 | dprintf("!duh -t 1 -p 0xffffffff13450080\n");
834 | dprintf(" will dump all window object create by process 0xffffffff13450080\n");
835 | }
836 |
837 | BOOL
838 | DumpUserHandles(
839 | IN PFILTER_CONTEXT Context
840 | )
841 | {
842 | UINT32 TotalHandleCounts;
843 | UINT32 HandleV;
844 |
845 | //
846 | // Check type
847 | //
848 |
849 | if (Context->Flags & OPT_FL_TYPE) {
850 | if (!IsUserTypeValid(Context->Type)) {
851 | dprintf("Invalid user object type\n");
852 | return FALSE;
853 | }
854 | }
855 |
856 | g_ExtControl->Execute(DEBUG_OUTCTL_IGNORE, ".reload nt", DEBUG_EXECUTE_NOT_LOGGED);
857 | g_ExtControl->Execute(DEBUG_OUTCTL_IGNORE, ".reload win32kbase.sys", DEBUG_EXECUTE_NOT_LOGGED);
858 | g_ExtControl->Execute(DEBUG_OUTCTL_IGNORE, ".reload win32kfull.sys", DEBUG_EXECUTE_NOT_LOGGED);
859 |
860 | TotalHandleCounts = GetUserObjCounts();
861 | if (!TotalHandleCounts) {
862 | dprintf("Have none user handle\n");
863 | return TRUE;
864 | }
865 |
866 | dprintf("Total 0x%x handles\n", TotalHandleCounts);
867 |
868 | for (HandleV = 1; HandleV < TotalHandleCounts; HandleV++)
869 | {
870 |
871 | HANDLEENTRY HandleEntry;
872 | KERNEL_HANDLEENTRY KernelHandleEntry;
873 | USER_TYPE_DESC CreateInfo;
874 | if (UserObjectGetEntry(HandleV, &HandleEntry, &KernelHandleEntry, &CreateInfo)) {
875 |
876 | //
877 | // owner == NULL mean this handle has been destroy
878 | //
879 |
880 | if (KernelHandleEntry.pOwner) {
881 |
882 | ULONG_PTR Handle;
883 | LPCSTR lpszOwnerType = "Unknown";
884 | ULONG_PTR pObject = NULL;
885 |
886 | //
887 | // read the handle from object
888 | // the user object always start with "HEAD"
889 | //
890 |
891 | if (!ReadPointer((ULONG64)KernelHandleEntry.pObject, &Handle)) {
892 | dprintf("can not handle at 0x%p\n", KernelHandleEntry.pObject);
893 | continue;
894 | }
895 |
896 | if (CreateInfo.CreateFlag & OCF_PROCESSOWNED) {
897 |
898 | //
899 | // the owner is PROCESSINFO
900 | // W32PROCESS
901 | //
902 |
903 | lpszOwnerType = "Process";
904 |
905 | if (!ReadPointer((ULONG64)KernelHandleEntry.pOwner, &pObject)) {
906 | dprintf("can not handle at 0x%p\n", KernelHandleEntry.pOwner);
907 | continue;
908 | }
909 |
910 | }else if (CreateInfo.CreateFlag & OCF_THREADOWNED) {
911 |
912 | //
913 | // The Owner is THREADINFO
914 | // W32THREAD
915 | //
916 |
917 | ULONG_PTR pWin32Thread;
918 | lpszOwnerType = "Thread";
919 |
920 | if (!ReadPointer((ULONG64)KernelHandleEntry.pOwner, &pWin32Thread)) {
921 | dprintf("can not handle at 0x%p\n", KernelHandleEntry.pOwner);
922 | continue;
923 | }
924 |
925 | //
926 | // So here is _ETHREAD
927 | //
928 |
929 | if (GetFieldValue(pWin32Thread, "nt!_KTHREAD", "Process", pObject)) {
930 | dprintf("can not process at thread 0x%p\n", pWin32Thread);
931 | continue;
932 | }
933 |
934 |
935 | }else {
936 |
937 | }
938 |
939 | //dprintf("handle:0x%08x object=0x%p type=(%02d)%-14s owner=0x%p process=0x%p createflag=0x%04x\n",
940 | // (ULONG64)Handle,
941 | // KernelHandleEntry.pObject,
942 | // HandleEntry.Type, GetUserTypeDesc(HandleEntry.Type),
943 | // KernelHandleEntry.pOwner, pObject, CreateInfo.CreateFlag
944 | //);
945 |
946 | if ((Context->Flags & OPT_FL_PROC && Context->Process != (PVOID)pObject) ||
947 | (Context->Flags & OPT_FL_TYPE && Context->Type != (int)HandleEntry.Type)){
948 | continue;
949 | }
950 |
951 | ExtOutDml("handle=0x%08x object=0x%p " \
952 | "process=0x%p type=(%02d)%-14s\n",
953 | (ULONG64)Handle, (ULONG64)Handle,
954 | KernelHandleEntry.pObject,
955 | pObject, pObject,
956 | HandleEntry.Type, GetUserTypeDesc(HandleEntry.Type)
957 | );
958 |
959 | }
960 | }
961 |
962 | if (CheckControlC() == TRUE) {
963 | dprintf("user control-c break\n");
964 | break;
965 | }
966 | }
967 |
968 | return TRUE;
969 | }
970 |
971 |
972 | EXTERN_C
973 | HRESULT
974 | CALLBACK
975 | duh(PDEBUG_CLIENT4 Client, PCSTR args)
976 | {
977 |
978 | CStringA strCmds;
979 |
980 | int argc;
981 | PSTR* argv;
982 | FILTER_CONTEXT FilterContext = {0};
983 |
984 | strCmds.Format("!duh %s", args);
985 | argv = CommandLineToArgvA(strCmds, &argc);
986 | CSimpleOptA Args(argc, argv, g_Options);
987 |
988 | while (Args.Next()) {
989 | if (Args.LastError() == SO_SUCCESS) {
990 | switch (Args.OptionId())
991 | {
992 | case OPT_FL_PROC:
993 | FilterContext.Flags |= OPT_FL_PROC;
994 | FilterContext.Process = (PVOID)strtoull(Args.OptionArg(), NULL, 16);
995 | break;
996 | case OPT_FL_TYPE:
997 | FilterContext.Flags |= OPT_FL_TYPE;
998 | FilterContext.Type = strtol(Args.OptionArg(), NULL, 10);
999 | break;
1000 |
1001 | case OPT_HELP:
1002 | ShowDumpUserHandleHelp();
1003 | return S_OK;
1004 | default:
1005 | break;
1006 | }
1007 | }
1008 | }
1009 |
1010 | INIT_API();
1011 | DumpUserHandles(&FilterContext);
1012 | EXIT_API();
1013 |
1014 | return S_OK;
1015 | }
1016 |
1017 |
--------------------------------------------------------------------------------
/handle.hpp:
--------------------------------------------------------------------------------
1 |
2 | typedef struct _ENTRY
3 | {
4 | ULONG_PTR HandleNextFree;
5 | ULONG ProcessIdOrSome;
6 | USHORT DirOrType;
7 | UCHAR Type;
8 | UCHAR field_F;
9 | ULONG_PTR field_10;
10 | }ENTRY, *PENTRY;
11 |
12 | typedef struct _LOOKUP_ENTRY
13 | {
14 | PVOID pLock;
15 | PVOID pObject;
16 | }LOOKUP_ENTRY, *PLOOKUP_ENTRY;
17 |
18 | typedef struct _ENTRYDATALOOKUPTABLE
19 | {
20 | PLOOKUP_ENTRY *ppLookupEntries;
21 | ULONG Counts;
22 | LOOKUP_ENTRY LookupEntries[1];
23 | }ENTRYDATALOOKUPTABLE, *PENTRYDATALOOKUPTABLE;
24 |
25 | typedef struct _HANDLEENTRYTABLE
26 | {
27 | PENTRY pEntries;
28 | ULONG Counts;
29 | ULONG LastFreeIndex;
30 | ULONG CurDirIndex;
31 | ULONG CurLookupIndex;
32 | PENTRYDATALOOKUPTABLE pEntryDataLookupTable;
33 | //ENTRY Entries[1];
34 | }HANDLEENTRYTABLE, *PHANDLEENTRYTABLE;
35 |
36 | typedef struct _HANDLEENTRYDIR
37 | {
38 | UCHAR bFilled;
39 | UCHAR field_1;
40 | USHORT DirCounts;
41 | ULONG field_4;
42 | PHANDLEENTRYTABLE pEntryTable[0x100];
43 | ULONG MaxDirGdiHandleCount;
44 | ULONG field_80C;
45 | }HANDLEENTRYDIR, *PHANDLEENTRYDIR;
46 |
47 |
48 | typedef struct _HANDLEMGR
49 | {
50 | ULONG TotalGdiHandleCounts;
51 | ULONG CurrentGdiHandleCounts;
52 | ULONG MaxGdiHandleCountSystem;
53 | ULONG field_C;
54 | PHANDLEENTRYDIR pHandleEntryDir;
55 | PULONG pHandleValueBackup;
56 | }HANDLEMGR, *PHANDLEMGR;
57 |
58 |
59 | typedef struct _HANDLEENTRY
60 | {
61 | ULONG_PTR ObjectOffset;
62 | ULONG_PTR ThreadOrProcessId;
63 | PVOID rpDisk;
64 | UCHAR Type;
65 | UCHAR field_19;
66 | USHORT wUniq;
67 | ULONG field_1C;
68 | }HANDLEENTRY, *PHANDLEENTRY;
69 |
70 |
71 | typedef struct tagSHAREDINFO
72 | {
73 | PVOID psi;
74 | PHANDLEENTRY aheList;
75 | ULONG aheSize;
76 | ULONG field_14;
77 | PVOID dispInfo;
78 | }SHAREDINFO, *PSHAREDINFO;
79 |
80 |
81 | typedef struct _KERNEL_HANDLEENTRY
82 | {
83 | PVOID pObject;
84 | PVOID pOwner;
85 | PVOID field_10;
86 | }KERNEL_HANDLEENTRY, *PKERNEL_HANDLEENTRY;
87 |
88 | typedef struct _USER_TYPE_DESC
89 | {
90 | PVOID fnDestroy;
91 | ULONG Tag;
92 | ULONG CreateFlag;
93 | ULONG field_10;
94 | ULONG field_14;
95 | }USER_TYPE_DESC, *PUSER_TYPE_DESC;
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/help.cxx:
--------------------------------------------------------------------------------
1 |
2 | #include "stdafx.h"
3 |
4 |
5 | char *gaszHelp[] = {
6 | "=======================================================================\n"
7 | ,"win32k debugger extentions:\n"
8 | ,"author: pgboy\n"
9 | ,"-----------------------------------------------------------------------\n"
10 | ,"\n"
11 | ,"gh [object handle] -- HMGR entry of handle (GDI object like DC/BITMAP/PALETTE etc)\n"
12 | ,"uh [object handle] -- USER entry of handle (USER object like WINDOW/MENU etc)\n"
13 | ,"duh [-h] -- Dump USER entry of handle (USER object like WINDOW/MENU etc)\n"
14 | ,"dgh [-h] -- Dump HMGR entry of handle (GDI object like DC/BITMAP/PALETTE etc)\n"
15 | ,"dpsurf [SURFACE ptr] -- SURFACE\n"
16 | ,"dpso [SURFOBJ ptr] -- SURFACE struct from SURFOBJ\n"
17 | ,"dr [REGION ptr] -- REGION\n"
18 | ,"cr [REGION ptr] -- check REGION\n"
19 | ,"dppal [PALETTE ptr] -- PALETTE\n"
20 | ,"=======================================================================\n"
21 | ,NULL
22 | };
23 |
24 | EXTERN_C
25 | HRESULT CALLBACK
26 | help(PDEBUG_CLIENT4 Client, PCSTR args)
27 | {
28 | for (char **ppsz = gaszHelp; *ppsz; ppsz++)
29 | dprintf("%s", *ppsz);
30 | return S_OK;
31 | }
32 |
--------------------------------------------------------------------------------
/object/palette.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | struct _PALETTE;
6 | typedef struct _PALETTE PALETTE;
7 |
8 | typedef union _HDEVPPAL
9 | {
10 | HANDLE hdev;
11 | PALETTE* ppal;
12 | } HDEVPPAL;
13 |
14 | typedef struct _PALETTE
15 | {
16 | HPALETTE Handle;
17 | ULONG_PTR field_8;
18 | ULONG_PTR field_10;
19 | ULONG flPal;
20 | ULONG cEntries;
21 | ULONG ulTime;
22 | ULONG field_24;
23 | HDC hdcHead;
24 | HDEVPPAL hSelected;
25 | ULONG cRefhpal;
26 | ULONG cRefRegular;
27 | ULONG field_40;
28 | ULONG field_44;
29 | PVOID ptransFore;
30 | PVOID ptransCurrent;
31 | PVOID ptransOld;
32 | HANDLE hcmXform;
33 | PALETTE* ppalNext;
34 | PVOID apalColor;
35 | PVOID ppalColor;
36 | PVOID apalColorTable;
37 | }PALETTE ,*PPALETTE;
38 |
39 |
40 |
--------------------------------------------------------------------------------
/object/region.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #define NEG_INFINITY 0x80000000
6 | #define POS_INFINITY 0x7fffffff
7 |
8 |
9 | typedef struct _BASEOBJECT
10 | {
11 | HANDLE hHmgr;
12 | PVOID pEntry;
13 | LONG cExclusiveLock;
14 | PVOID Tid;
15 | } BASEOBJECT, *POBJ;
16 |
17 |
18 | typedef struct _SCAN
19 | {
20 | ULONG cWalls;
21 | LONG yTop;
22 | LONG yBottom;
23 | LONG ai_x[1];
24 | }SCAN, *PSCAN;
25 |
26 | typedef struct _REGION
27 | {
28 | HANDLE hHmgr;
29 | ULONG_PTR cExclusiveLock;
30 | PVOID Tid;
31 | ULONG sizeObj;
32 | ULONG UniqueId;
33 | ULONG cRefs;
34 | ULONG field_24;
35 | PSCAN pscnTail;
36 | LIST_ENTRY List;
37 | ULONG field_40;
38 | ULONG field_44;
39 | ULONG field_48;
40 | ULONG field_4C;
41 | ULONG sizeRgn;
42 | ULONG cScans;
43 | RECTL rcl;
44 | SCAN scan;
45 | }REGION;
46 |
--------------------------------------------------------------------------------
/object/suface.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #define STYPE_BITMAP 0L
6 | #define STYPE_DEVICE 1L
7 | #define STYPE_JOURNAL 2L
8 | #define STYPE_DEVBITMAP 3L
9 |
10 | #define BMF_1BPP 1L
11 | #define BMF_4BPP 2L
12 | #define BMF_8BPP 3L
13 | #define BMF_16BPP 4L
14 | #define BMF_24BPP 5L
15 | #define BMF_32BPP 6L
16 | #define BMF_4RLE 7L
17 | #define BMF_8RLE 8L
18 |
19 | #define PDEV_SURFACE 0x80000000 // specifies the surface is for a pdev
20 | #define ABORT_SURFACE 0x40000000 // Abort operations on the surface
21 | #define DYNAMIC_MODE_PALETTE 0x20000000 // The surface is a Device Dependent
22 | // Bitmap whose palette was added
23 | // by GreDynamicModeChange
24 | #define UNREADABLE_SURFACE 0x10000000 // Reads not allowed from this surface
25 | #define PALETTE_SELECT_SET 0x08000000 // We wrote palette in at select time.
26 | #define DELETEABLE_PUBLIC_SURF 0x04000000 // deleteable even though user made public
27 | #define BANDING_SURFACE 0x02000000 // used for banding
28 | #define LAZY_DELETE_SURFACE 0x01000000 // DeleteObject has been called
29 | #define DDB_SURFACE 0x00800000 // Non-monochrome Device Dependent
30 | // Bitmap surface
31 |
32 | #define SURF_FLAGS 0xff800000 // Logical OR of all above flags
33 |
34 |
35 |
36 | typedef struct _SURFOBJ
37 | {
38 | HANDLE dhsurf;
39 | HANDLE hsurf;
40 | HANDLE dhpdev;
41 | HANDLE hdev;
42 | SIZEL sizlBitmap;
43 | ULONG cjBits;
44 | int field_2C;
45 | PVOID pvBits;
46 | PVOID pvScan0;
47 | LONG lDelta;
48 | ULONG iUniq;
49 | ULONG iBitmapFormat;
50 | WORD iType;
51 | WORD fjBitmap;
52 | }SURFOBJ, *PSURFOBJ;
53 |
54 | typedef struct _SURFACE
55 | {
56 | HANDLE Handle;
57 | HANDLE field_8;
58 | HANDLE field_10;
59 | SURFOBJ so;
60 | __int64 field_68;
61 | int field_70;
62 | int field_74;
63 | int field_78;
64 | int field_7C;
65 | PVOID pPal;
66 | __int64 field_88;
67 | __int64 field_90;
68 | __int64 field_98;
69 | __int64 field_A0;
70 | int field_A8;
71 | int field_AC;
72 | __int64 field_B0;
73 | int ProcessId;
74 | int field_BC;
75 | __int64 field_C0;
76 | __int64 field_C8;
77 | int field_D0;
78 | int field_D4;
79 | __int64 field_D8;
80 | int field_E0;
81 | int field_E4;
82 | __int64 field_E8;
83 | LIST_ENTRY list1;
84 | __int64 field_100;
85 | __int64 field_108;
86 | __int64 field_110;
87 | __int64 field_118;
88 | __int64 field_120;
89 | __int64 field_128;
90 | __int64 field_130;
91 | __int64 field_138;
92 | __int64 field_140;
93 | int field_148;
94 | int field_14C;
95 | __int64 field_150;
96 | __int64 field_158;
97 | __int64 field_160;
98 | __int64 field_168;
99 | __int64 field_170;
100 | __int64 field_178;
101 | __int64 field_180;
102 | __int64 field_188;
103 | __int64 field_190;
104 | __int64 field_198;
105 | __int64 field_1A0;
106 | __int64 field_1A8;
107 | __int64 field_1B0;
108 | __int64 field_1B8;
109 | __int64 field_1C0;
110 | LIST_ENTRY list2;
111 | __int64 field_1D8;
112 | __int64 field_1E0;
113 | __int64 field_1E8;
114 | __int64 field_1F0;
115 | __int64 field_1F8;
116 | __int64 field_200;
117 | __int64 field_208;
118 | __int64 field_210;
119 | __int64 field_218;
120 | int field_220;
121 | int field_224;
122 | int field_228;
123 | int field_22C;
124 | __int64 field_230;
125 | __int64 field_238;
126 | __int64 field_240;
127 | __int64 field_248;
128 | int field_250;
129 | int field_254;
130 | __int64 field_258;
131 | __int64 field_260;
132 | __int64 field_268;
133 | __int64 field_270;
134 | }SURFACE, *PSURFACE;
135 |
136 |
--------------------------------------------------------------------------------
/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // win32kext.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 |
10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
11 | // Windows Header Files:
12 | #include
13 | #include
14 |
15 |
16 | // TODO: reference additional headers your program requires here
17 |
18 |
19 | #ifdef _WIN64
20 | #define KDEXT_64BIT
21 | #else
22 | #define KDEXT_32BIT
23 | #endif
24 |
25 | #include
26 | #include
27 |
28 | #pragma comment(lib, "dbgeng.lib")
29 |
30 | #ifdef _DEBUG
31 | # define DEBUGPRINT dprintf
32 | #else
33 | # define DEBUGPRINT(...) __noop
34 | #endif
35 |
36 | #ifdef WIN32KEXT_EXPORTS
37 | #define WIN32KEXT_API __declspec(dllexport)
38 | #else
39 | #define WIN32KEXT_API __declspec(dllimport)
40 | #endif
41 |
42 |
43 | //
44 | // windbg pointer is 64-bit
45 | //
46 |
47 | typedef ULONG64 WDBG_PTR, *PWDBG_PTR;
48 |
--------------------------------------------------------------------------------
/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/utils.cxx:
--------------------------------------------------------------------------------
1 |
2 | #include "stdafx.h"
3 | #include "utils.hpp"
4 |
5 | PCHAR*
6 | CommandLineToArgvA(
7 | LPCSTR CmdLine,
8 | int* _argc
9 | )
10 | {
11 | PCHAR* argv;
12 | PCHAR _argv;
13 | ULONG len;
14 | ULONG argc;
15 | CHAR a;
16 | ULONG i, j;
17 |
18 | BOOLEAN in_QM;
19 | BOOLEAN in_TEXT;
20 | BOOLEAN in_SPACE;
21 |
22 | len = strlen(CmdLine);
23 | i = ((len + 2) / 2) * sizeof(PVOID) + sizeof(PVOID);
24 |
25 | argv = (PCHAR*)LocalAlloc(0,
26 | i + (len + 2) * sizeof(CHAR));
27 | if (!argv){
28 | return NULL;
29 | }
30 |
31 | _argv = (PCHAR)(((PUCHAR)argv) + i);
32 |
33 | argc = 0;
34 | argv[argc] = _argv;
35 | in_QM = FALSE;
36 | in_TEXT = FALSE;
37 | in_SPACE = TRUE;
38 | i = 0;
39 | j = 0;
40 |
41 | while (a = CmdLine[i]) {
42 | if (in_QM) {
43 | if (a == '\"') {
44 | in_QM = FALSE;
45 | }
46 | else {
47 | _argv[j] = a;
48 | j++;
49 | }
50 | }
51 | else {
52 | switch (a) {
53 | case '\"':
54 | in_QM = TRUE;
55 | in_TEXT = TRUE;
56 | if (in_SPACE) {
57 | argv[argc] = _argv + j;
58 | argc++;
59 | }
60 | in_SPACE = FALSE;
61 | break;
62 | case ' ':
63 | case '\t':
64 | case '\n':
65 | case '\r':
66 | if (in_TEXT) {
67 | _argv[j] = '\0';
68 | j++;
69 | }
70 | in_TEXT = FALSE;
71 | in_SPACE = TRUE;
72 | break;
73 | default:
74 | in_TEXT = TRUE;
75 | if (in_SPACE) {
76 | argv[argc] = _argv + j;
77 | argc++;
78 | }
79 | _argv[j] = a;
80 | j++;
81 | in_SPACE = FALSE;
82 | break;
83 | }
84 | }
85 | i++;
86 | }
87 | _argv[j] = '\0';
88 | argv[argc] = NULL;
89 |
90 | (*_argc) = argc;
91 | return argv;
92 | }
--------------------------------------------------------------------------------
/utils.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | PCHAR*
5 | CommandLineToArgvA(
6 | LPCSTR CmdLine,
7 | int* _argc
8 | );
--------------------------------------------------------------------------------
/win32kext.def:
--------------------------------------------------------------------------------
1 | LIBRARY WIN32KEXT
2 |
3 | EXPORTS
4 | dr
5 | cr
6 | uh
7 | gh
8 | dgh
9 | duh
10 | dpsurf
11 | dpso
12 | dppal
13 | help
14 | fl
--------------------------------------------------------------------------------
/win32kext.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32kext", "win32kext.vcxproj", "{53C877EF-71AF-4F96-B560-EFEE166B28C6}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}.Debug|x64.ActiveCfg = Debug|x64
17 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}.Debug|x64.Build.0 = Debug|x64
18 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}.Debug|x86.ActiveCfg = Debug|Win32
19 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}.Debug|x86.Build.0 = Debug|Win32
20 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}.Release|x64.ActiveCfg = Release|x64
21 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}.Release|x64.Build.0 = Release|x64
22 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}.Release|x86.ActiveCfg = Release|Win32
23 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/win32kext.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {53C877EF-71AF-4F96-B560-EFEE166B28C6}
23 | Win32Proj
24 | win32kext
25 | 10.0
26 | win32kext
27 |
28 |
29 |
30 | DynamicLibrary
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | DynamicLibrary
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | DynamicLibrary
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | DynamicLibrary
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | true
78 |
79 |
80 | false
81 |
82 |
83 | false
84 |
85 |
86 |
87 |
88 |
89 | Level3
90 | Disabled
91 | WIN32;_DEBUG;_WINDOWS;_USRDLL;WIN32KEXT_EXPORTS;%(PreprocessorDefinitions)
92 |
93 |
94 | Windows
95 | true
96 | win32kext.def
97 |
98 |
99 |
100 |
101 | Use
102 | Level3
103 | Disabled
104 | _DEBUG;_WINDOWS;_USRDLL;WIN32KEXT_EXPORTS;%(PreprocessorDefinitions)
105 | MultiThreadedDebug
106 | 4838
107 |
108 |
109 | Windows
110 | true
111 | win32kext.def
112 |
113 |
114 |
115 |
116 | Level3
117 |
118 |
119 | MaxSpeed
120 | true
121 | true
122 | WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN32KEXT_EXPORTS;%(PreprocessorDefinitions)
123 | MultiThreaded
124 | 4838
125 |
126 |
127 | Windows
128 | true
129 | true
130 | true
131 | win32kext.def
132 |
133 |
134 |
135 |
136 | Level3
137 | Use
138 | MaxSpeed
139 | true
140 | true
141 | NDEBUG;_WINDOWS;_USRDLL;WIN32KEXT_EXPORTS;%(PreprocessorDefinitions)
142 | MultiThreaded
143 |
144 |
145 | Windows
146 | true
147 | true
148 | true
149 | win32kext.def
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | false
169 |
170 |
171 | false
172 |
173 |
174 | false
175 |
176 |
177 | false
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | Create
187 | Create
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/win32kext.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {90f31c2f-e578-4b73-b3e7-9014e5df3ba1}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files\object
35 |
36 |
37 | Header Files\object
38 |
39 |
40 | Header Files\object
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files
47 |
48 |
49 |
50 |
51 | Source Files
52 |
53 |
54 | Source Files
55 |
56 |
57 | Source Files
58 |
59 |
60 | Source Files
61 |
62 |
63 | Source Files
64 |
65 |
66 | Source Files
67 |
68 |
69 | Source Files
70 |
71 |
72 | Source Files
73 |
74 |
75 |
76 |
77 | Source Files
78 |
79 |
80 |
--------------------------------------------------------------------------------