├── LICENSE
├── README.md
├── TWindbg
├── TWindbg.py
├── color.py
├── command.py
├── command_handler.py
├── context.py
└── utils.py
├── batch
├── TWindbg_x64.bat
├── TWindbg_x86.bat
└── del_windbg_reg.bat
├── img
├── context.PNG
└── tel.PNG
├── matrix_theme.WEW
└── matrix_theme.reg
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Bruce Chen
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 | > [!Caution]
2 | > This project is no longer maintained due to several reasons:
3 | > * The official pykd is no longer updated.
4 | > * Windbg has become an excellent tool. It has a nice UI, and if you need telescope there's also a [script](https://github.com/0vercl0k/windbg-scripts/tree/master/telescope) that'll do the work. IMO there's no need to use this tool anymore.
5 | >
6 | > I would like to thank anyone that has supported this project. I had a lot of fun writing this tool :)
7 |
8 | ---
9 |
10 | [](https://github.com/bruce30262/TWindbg/)
11 | [](https://codeclimate.com/github/bruce30262/TWindbg)
12 | [](https://codeclimate.com/github/bruce30262/TWindbg)
13 | [](http://choosealicense.com/licenses/mit/)
14 |
15 |
16 | # TWindbg
17 | PEDA-like debugger UI for WinDbg
18 |
19 | 
20 |
21 | # Introduction
22 | This is a windbg extension ( using [pykd](https://githomelab.ru/pykd/pykd) ) to let user having a [PEDA-like](https://github.com/longld/peda) debugger UI in WinDbg.
23 | It will display the following context in each step/trace:
24 | - Registers
25 | - Disassembled code near PC
26 | - Contents of the stack pointer ( with basic smart dereference )
27 |
28 | It also supports some peda-like commands ( see the [support commands](#support-commands) section )
29 |
30 | For now it supports both x86 & x64 WinDbg.
31 |
32 | # Dependencies
33 | * Python 3
34 |
35 | > I decided to drop the support of Python2.7 since it has [reached the EOL](https://www.python.org/doc/sunset-python-2/). I believe the project is Python2/3 compatible, however there might exist some issues in pykd and can cause different behavior in Python2/3. Since now the project will only be tested on Python3, I strongly suggest using TWindbg on Python3 instead of Python 2.7. If you still want to use it on Python 2.7, feel free to fork the project and do the development.
36 |
37 | * [pykd](https://githomelab.ru/pykd/pykd)
38 |
39 | # Installation
40 | * Install Python3
41 | * Install pykd
42 | - Download [Pykd-Ext](https://githomelab.ru/pykd/pykd-ext/-/wikis/Downloads), unpack `pykd.dll` to the `[WinDbg Directory]\x86(or x64)\winext\` directory.
43 | + This will allow you to run python in Windbg.
44 | - In the Windbg command line, enter command `.load pykd` to load the pykd module.
45 | - Enter `!pip install pykd` to install the pykd python package.
46 | + Upgrade the pykd module with command `!pip install --upgrade pykd`.
47 | + If something went wrong during the installation with `pip install`, try installing the wheel package instead of the one on PyPI. You can download the wheel package [here](https://githomelab.ru/pykd/pykd/-/wikis/All%20Releases).
48 | * Download the repository
49 | * Install the matrix theme by double-clicking the [matrix_theme.reg](/matrix_theme.reg)
50 | - The matrix theme is required for letting the [color theme](/TWindbg/color.py) work in TWindbg
51 | - You can preview the theme by importing the [matrix_theme.WEW](/matrix_theme.WEW) workspace into WinDbg.
52 | * Copy the [TWindbg](/TWindbg) folder into `[WinDbg Directory]\x64\winext\` & `[WinDbg Directory]\x86\winext\`
53 |
54 | # Usage
55 | ## Launch TWindbg manually
56 | * Open an executable or attach to a process with WinDbg
57 | * Use `.load pykd` to load the `pykd` extension
58 | * Use `!py -g winext\TWindbg\TWindbg.py` to launch TWindbg
59 |
60 | ## Launch TWindbg with command
61 | ```
62 | [PATH_TO_WINDBG] -a pykd -c "!py -g winext\TWindbg\TWindbg.py"
63 | ```
64 | Or you can write a [simple batch file](/batch/TWindbg_x64.bat) for the sake of convenience.
65 |
66 | After that you can just use `t` or `p` to see if the extension is working.
67 |
68 | # Support Commands
69 | * `TWindbg`: List all the command in TWindbg
70 | * `ctx`: Print out the current context
71 | * `tel / telescope`: Display memory content at an address with smart dereferences
72 | 
73 |
74 | # Note
75 | Maybe ( just maybe ) I'll add more command to make WinDbg behave more like PEDA ( or other debugger like pwndbg, GEF... ) in the future.
76 |
--------------------------------------------------------------------------------
/TWindbg/TWindbg.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pykd
4 | import color
5 | import sys
6 | import command_handler
7 | import context
8 |
9 | # Init arch & context handler
10 | context.init_arch()
11 | context.init_context_handler()
12 | # TWindbg command wrapper
13 | command_handler.wrap_all_commands()
14 | # Print out the current context
15 | context.context_handler.print_context()
16 |
--------------------------------------------------------------------------------
/TWindbg/color.py:
--------------------------------------------------------------------------------
1 | RED = ("errfg", "wbg")
2 | ORANGE = ("warnfg", "wbg")
3 | BLUE = ("verbfg", "wbg")
4 | GRAY = ("subfg", "wbg")
5 | DARK_RED = ("srcstr", "wbg")
6 | GREEN = ("srccmnt", "wbg")
7 | WHITE = ("emphbg", "wbg")
8 | YELLOW = ("srcdrct", "wbg")
9 | LIME = ("wfg", "wbg")
10 | LIME_HIGHLIGHT = ("wbg", "wfg")
11 |
12 | def red(content): return colorize(RED, content)
13 | def yellow(content): return colorize(YELLOW, content)
14 | def orange(content): return colorize(ORANGE, content)
15 | def blue(content): return colorize(BLUE, content)
16 | def gray(content): return colorize(GRAY, content)
17 | def dark_red(content): return colorize(DARK_RED, content)
18 | def green(content): return colorize(GREEN, content)
19 | def white(content): return colorize(WHITE, content)
20 | def lime(content): return colorize(LIME, content)
21 | def lime_highlight(content): return colorize(LIME_HIGHLIGHT, content)
22 | def colorize(col, content): return "
{}".format(col[0], col[1], content)
23 |
--------------------------------------------------------------------------------
/TWindbg/command.py:
--------------------------------------------------------------------------------
1 | import pykd
2 | import sys
3 | import context
4 | import color
5 | import traceback
6 |
7 | from utils import *
8 | from functools import wraps
9 |
10 | all_commands = [
11 | 'TWindbg',
12 | 'telescope',
13 | 'ctx'
14 | ]
15 |
16 | class CmdExecError(Exception):
17 | def __init__(self, errmsg):
18 | self.errmsg = errmsg
19 |
20 | def wrap_usage(func):
21 | @wraps(func)
22 | def wrap(*args, **kwargs):
23 | if len(args[0]) == 1 and args[0][0] == "help":
24 | print_usage(func.__doc__)
25 | return
26 | func(*args, **kwargs)
27 | return wrap
28 |
29 | def print_all_usage():
30 | global all_commands
31 | for cmd in all_commands:
32 | cmd_info = globals()[cmd].__doc__.split("\n")[0].split(":")[1]
33 | pykd.dprintln("{:15s}{}".format(cmd, cmd_info))
34 |
35 | @wrap_usage
36 | def TWindbg(args):
37 | """TWindbg: List all the command in TWindbg """
38 | if len(args) != 0:
39 | raise CmdExecError("Invalid argument number")
40 | banner = color.yellow("TWindbg: PEDA-like debugger UI for WinDbg\n")
41 | banner += color.gray("For latest update, check the project page: ")
42 | banner += color.white("https://github.com/bruce30262/TWindbg\n")
43 | banner += color.orange("Use \"[cmd] help\" for further command usage\n")
44 | pykd.dprintln(banner, dml=True)
45 | print_all_usage()
46 |
47 | @wrap_usage
48 | def ctx(args):
49 | """ctx: Print the current context"""
50 | context.context_handler.print_context()
51 |
52 | @wrap_usage
53 | def telescope(args):
54 | """telescope: Display memory content at an address with smart dereferences
55 | Usage: telescope/tel [addr] [line to display, default=8, maximum=100]
56 | """
57 | # check argument number
58 | if not arg_num_in_range(args, 1, 2):
59 | raise CmdExecError("Invalid argument number")
60 | # get start address and line number
61 | start_addr = to_addr(args[0])
62 | line_num = 8 if len(args) == 1 else to_int(args[1])
63 | # check valid address
64 | is_addr, errmsg = check_valid_addr(args[0])
65 | if not is_addr:
66 | raise CmdExecError(errmsg)
67 | # check valid line number
68 | if not check_in_range(line_num, 1, 100):
69 | raise CmdExecError("Invalid line number: {}, should be 1 ~ 100".format(args[1]))
70 |
71 | context.context_handler.print_nline_ptrs(start_addr, line_num)
72 |
--------------------------------------------------------------------------------
/TWindbg/command_handler.py:
--------------------------------------------------------------------------------
1 | import pykd
2 | import sys
3 | import traceback
4 | import command
5 |
6 | from utils import *
7 |
8 | def set_alias(a, v):
9 | pykd.dbgCommand("as {} {}".format(a, v))
10 |
11 | def wrap_command(cmd, real_cmd):
12 | set_alias(cmd, "!py -g winext\TWindbg\command_handler.py {}".format(real_cmd))
13 |
14 | def wrap_all_commands():
15 | for cmd in command.all_commands:
16 | wrap_command(cmd, cmd)
17 | wrap_command("tel", "telescope")
18 |
19 | class CommandHandler():
20 | def __init__(self, func):
21 | self.func = func
22 |
23 | def invoke(self, args):
24 | try:
25 | self.func(args)
26 | except command.CmdExecError as e:
27 | print_err(e.errmsg)
28 | print_usage(self.func.__doc__)
29 | except Exception:
30 | traceback.print_exc()
31 |
32 | if __name__ == "__main__":
33 | if len(sys.argv) >= 2: # user input TWindbg command
34 | cmd = sys.argv[1]
35 | if cmd in command.all_commands and hasattr(command, cmd): # if the command mudule has the corresponded method, call it
36 | func = getattr(command, cmd)
37 | CommandHandler(func).invoke(sys.argv[2::])
38 | else:
39 | print_err("Command: {} not found in TWindbg.".format(cmd))
40 |
41 |
--------------------------------------------------------------------------------
/TWindbg/context.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pykd
4 | import color
5 | import sys
6 | import traceback
7 |
8 | from utils import *
9 |
10 | ARCH = None
11 | PTRMASK = None
12 | PTRSIZE = None
13 | MAX_DEREF_DEPTH = 20
14 |
15 | def init_arch():
16 | global ARCH, PTRMASK, PTRSIZE
17 | cpu_mode = pykd.getCPUMode()
18 | if cpu_mode == pykd.CPUType.I386:
19 | ARCH = 'x86'
20 | PTRMASK = 0xffffffff
21 | PTRSIZE = 4
22 | elif cpu_mode == pykd.CPUType.AMD64:
23 | ARCH = 'x64'
24 | PTRMASK = 0xffffffffffffffff
25 | PTRSIZE = 8
26 | else:
27 | print_err("CPU mode: {} not supported.".format(cpu_mode))
28 | sys.exit(-1)
29 |
30 | def init_context_handler():
31 | global context_handler
32 | if 'context_handler' not in globals():
33 | context_handler = ContextHandler(Context())
34 |
35 | class Context():
36 | def __init__(self):
37 | self.regs_name = []
38 | self.seg_regs_name = ['cs', 'ds', 'es', 'fs', 'gs', 'ss']
39 | self.regs = {}
40 | self.eflags_tbl = {
41 | 0: "carry",
42 | 2: "parity",
43 | 4: "auxiliary",
44 | 6: "zero",
45 | 7: "sign",
46 | 8: "trap",
47 | 9: "interrupt",
48 | 10: "direction",
49 | 11: "overflow",
50 | 14: "nested",
51 | 16: "resume",
52 | 17: "virtualx86"
53 | }
54 | self.is_changed = {}
55 | self.sp_name = ""
56 | self.sp = None
57 | self.pc_name = ""
58 | self.pc = None
59 |
60 | self.init_regs_name()
61 | self.init_regs()
62 |
63 | def init_regs_name(self):
64 | if ARCH == 'x86':
65 | self.regs_name = ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
66 | self.sp_name = 'esp'
67 | self.pc_name = 'eip'
68 | else:
69 | self.regs_name = ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'rbp', 'rsp', 'rip']
70 | self.sp_name = 'rsp'
71 | self.pc_name = 'rip'
72 |
73 | def init_regs(self):
74 | for reg_name in self.regs_name + self.seg_regs_name:
75 | self.regs[reg_name] = None
76 | self.is_changed[reg_name] = False
77 |
78 | def update_regs(self):
79 | for reg_name in self.regs_name + self.seg_regs_name:
80 | reg_data = pykd.reg(reg_name)
81 | if reg_data != self.regs[reg_name]: # is changed
82 | self.is_changed[reg_name] = True
83 | else:
84 | self.is_changed[reg_name] = False
85 |
86 | self.regs[reg_name] = reg_data
87 | # update sp & pc
88 | self.sp = self.regs[self.sp_name]
89 | self.pc = self.regs[self.pc_name]
90 |
91 | class ContextHandler(pykd.eventHandler):
92 | def __init__(self, context):
93 | pykd.eventHandler.__init__(self)
94 | self.context = context
95 |
96 | def onExecutionStatusChange(self, status):
97 | if status == pykd.executionStatus.Break: # step, trace, ...
98 | self.print_context()
99 |
100 | def print_context(self):
101 | self.context.update_regs()
102 | pykd.dprintln(color.yellow("[------ Register --------------------------------------------------------------------------------------------]"), dml=True)
103 | self.print_regs()
104 | pykd.dprintln(color.yellow("[------ Code ------------------------------------------------------------------------------------------------]"), dml=True)
105 | self.print_code()
106 | pykd.dprintln(color.yellow("[------ Stack -----------------------------------------------------------------------------------------------]"), dml=True)
107 | self.print_stack()
108 | pykd.dprintln(color.yellow("[------------------------------------------------------------------------------------------------------------]"), dml=True)
109 |
110 | def print_regs(self):
111 | self.print_general_regs()
112 | self.print_seg_regs()
113 | self.print_eflags()
114 |
115 | def print_general_regs(self):
116 | for reg_name in self.context.regs_name:
117 | reg_data = self.context.regs[reg_name]
118 | reg_str = '{:3}: '.format(reg_name.upper())
119 | reg_color = self.set_reg_color(reg_name, color_changed=color.red, color_unchanged=color.lime)
120 | pykd.dprint(reg_color(reg_str), dml=True)
121 |
122 | # if reg_data is a valid virtual address and is able to be dereferenced, print it with print_ptrs(), or else just print it directly
123 | if pykd.isValid(reg_data) and ( deref_ptr(reg_data) != None ):
124 | self.print_ptrs(reg_data)
125 | else:
126 | pykd.dprintln("{:#x}".format(reg_data))
127 |
128 | def print_seg_regs(self):
129 | first_print = True
130 | for reg_name in self.context.seg_regs_name:
131 | reg_data = self.context.regs[reg_name]
132 | reg_str = '{:2}={:#x}'.format(reg_name.upper(), reg_data)
133 | reg_color = self.set_reg_color(reg_name, color_changed=color.red, color_unchanged=color.green)
134 |
135 | if first_print:
136 | pykd.dprint(reg_color(reg_str), dml=True)
137 | first_print = False
138 | else:
139 | pykd.dprint(" | " + reg_color(reg_str), dml=True)
140 | pykd.dprintln("")
141 |
142 | def print_eflags(self):
143 | eflags = pykd.reg('efl')
144 | eflags_str = color.green("EFLAGS: {:#x}".format(eflags))
145 | eflags_str += " ["
146 | for bit, flag_name in self.context.eflags_tbl.items():
147 | is_set = eflags & (1< ".format(ptr)
192 | # handle last two's format
193 | last_ptr, last_val = ptr_values[-2], ptr_values[-1]
194 | if is_cyclic:
195 | ptrs_str += "{:#x} --> {:#x}".format(last_ptr, last_val) + color.dark_red(" ( cyclic dereference )")
196 | else:
197 | ptrs_str += self.enhance_type(last_ptr, last_val)
198 | pykd.dprintln(ptrs_str, dml=True)
199 |
200 | def enhance_type(self, ptr, val):
201 | ret_str = ""
202 | if is_executable(ptr): # code page
203 | symbol = pykd.findSymbol(ptr) + ":"
204 | asm_str = disasm(ptr)[1]
205 | ret_str = "{:#x}".format(ptr)
206 | ret_str += color.gray(" ({:45s}{})".format(symbol, asm_str))
207 | else:
208 | ret_str = "{:#x} --> {:#x}".format(ptr, val)
209 | val_str = get_string(ptr)
210 | if val_str: # val is probably a string
211 | ret_str += color.white(" (\"{}\")".format(val_str))
212 | return ret_str
213 |
214 | def smart_dereference(self, ptr):
215 | ptr_values, is_cyclic = [ptr], False
216 | deref_depth = 0
217 | val = deref_ptr(ptr)
218 |
219 | while self.can_chain_pointer(val, deref_depth, is_cyclic):
220 | deref_depth += 1
221 | ptr_values.append(val)
222 | # Check if the newly pushed value is in ptr_values[:-1:]
223 | # If it does means there's a cyclic dereference in the current pointer chain
224 | # Otherwise the newly pushed value will become the new pointer to be dereferenced next
225 | if val in ptr_values[:-1:]:
226 | is_cyclic = True
227 | else:
228 | val = deref_ptr(val)
229 |
230 | return ptr_values, is_cyclic
231 |
232 | def can_chain_pointer(self, val, deref_depth, is_cyclic):
233 | """
234 | Check if we can keep chaining the pointer list, which should match the following conditions:
235 | - val ( The newly dereferenced value ) should not be None
236 | - deref_depth ( deference depth ) should not exceed MAX_DEREF_DEPTH
237 | - No cyclic dereference is detected
238 | """
239 | return ( val != None ) and ( deref_depth <= MAX_DEREF_DEPTH ) and not is_cyclic
240 |
241 |
--------------------------------------------------------------------------------
/TWindbg/utils.py:
--------------------------------------------------------------------------------
1 | import pykd
2 | import color
3 | import context
4 | import string
5 |
6 | def to_int(val):
7 | """
8 | Convert a string to int number
9 | from https://github.com/longld/peda
10 | """
11 | try:
12 | return int(str(val), 0)
13 | except:
14 | return None
15 |
16 | def to_addr(val):
17 | """ Convert a value to a memory address """
18 | try:
19 | addr = to_int(get_expr(val))
20 | if pykd.isValid(addr):
21 | return addr & context.PTRMASK
22 | except:
23 | pass
24 |
25 | return None
26 |
27 | def get_expr(val):
28 | """ Convert a windbg expression to real value """
29 | try:
30 | return pykd.expr(val)
31 | except:
32 | return None
33 |
34 | def print_err(msg):
35 | pykd.dprintln(color.red(msg), dml=True)
36 |
37 | def print_usage(doc_str):
38 | pykd.dprintln(color.blue(doc_str), dml=True)
39 |
40 | def check_in_range(val, low, up):
41 | """ check if low <= val <= up """
42 | int_val = to_int(val)
43 | if int_val == None:
44 | return False
45 | elif low <= int_val and int_val <= up:
46 | return True
47 | else:
48 | return False
49 |
50 | def check_valid_addr(val):
51 | """ check if val is valid memory address """
52 | addr, real_val = to_addr(val), get_expr(val)
53 | if not addr:
54 | errmsg = "Invalid address: "
55 | if real_val != None:
56 | errmsg += "{:#x}".format(real_val & context.PTRMASK)
57 | else:
58 | errmsg += "{}".format(val)
59 | return False, errmsg
60 | else:
61 | return True, None
62 |
63 | def arg_num_in_range(args, low, up):
64 | """ check if low <= len(args) <= up """
65 | return check_in_range(len(args), low, up)
66 |
67 | def disasm(addr):
68 | """ disassemble, return opcodes and assembly string """
69 | resp = pykd.disasm().disasm(addr).split(" ")
70 | op_str = resp[1]
71 | asm_str = ' '.join(c for c in resp[2::]).strip()
72 | return op_str, asm_str
73 |
74 | def is_executable(addr):
75 | if pykd.isKernelDebugging(): return False # we need to find a way to get the memory protection information in kernel debug mode
76 | if "Execute" in str(pykd.getVaProtect(addr)):
77 | return True
78 | else:
79 | return False
80 |
81 | def load_str(load_str_func, ptr):
82 | """ Load string with pykd function """
83 | max_length = 30
84 | try:
85 | s = load_str_func(ptr)
86 | if not all(c in string.printable for c in s):
87 | return None
88 | if len(s) > max_length:
89 | return s[:max_length:] + "..."
90 | else:
91 | return s
92 | except:
93 | return None
94 |
95 | def get_string(ptr):
96 | """ try to get string from a pointer """
97 |
98 | ret = load_str(pykd.loadWStr, ptr) # try load WString (unicode) first
99 | if not ret: ret = load_str(pykd.loadCStr, ptr) # if failed, load CStr ( ascii )
100 |
101 | return ret
102 |
103 | def deref_ptr(ptr):
104 | try:
105 | return pykd.loadPtrs(ptr, 1)[0] & context.PTRMASK
106 | except pykd.MemoryException:
107 | return None
108 |
--------------------------------------------------------------------------------
/batch/TWindbg_x64.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -a pykd -c "!py -g winext\TWindbg\TWindbg.py"
3 |
--------------------------------------------------------------------------------
/batch/TWindbg_x86.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe" -a pykd -c "!py -g winext\TWindbg\TWindbg.py"
3 |
--------------------------------------------------------------------------------
/batch/del_windbg_reg.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | reg delete HKCU\Software\Microsoft\Windbg
3 |
--------------------------------------------------------------------------------
/img/context.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bruce30262/TWindbg/afb9f7851917cc13aeb1583fae825d42d7115b0e/img/context.PNG
--------------------------------------------------------------------------------
/img/tel.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bruce30262/TWindbg/afb9f7851917cc13aeb1583fae825d42d7115b0e/img/tel.PNG
--------------------------------------------------------------------------------
/matrix_theme.WEW:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bruce30262/TWindbg/afb9f7851917cc13aeb1583fae825d42d7115b0e/matrix_theme.WEW
--------------------------------------------------------------------------------
/matrix_theme.reg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bruce30262/TWindbg/afb9f7851917cc13aeb1583fae825d42d7115b0e/matrix_theme.reg
--------------------------------------------------------------------------------