├── .clang-format ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── assets ├── ext.png └── help.png ├── cmake └── Binary2Header.cmake ├── jstests └── test.js ├── src ├── binding │ └── dbgeng │ │ ├── binding_client.cpp │ │ ├── binding_client2.cpp │ │ ├── binding_control.cpp │ │ ├── binding_data_spaces.cpp │ │ ├── binding_dbgeng.cpp │ │ ├── binding_dbgeng.h │ │ ├── binding_registers.cpp │ │ ├── binding_symbols.cpp │ │ ├── binding_system_objects.cpp │ │ └── binding_system_objects2.cpp ├── callbacks │ ├── captured_output_callbacks.cpp │ ├── captured_output_callbacks.h │ ├── standard_event_callbacks.cpp │ ├── standard_event_callbacks.h │ ├── standard_output_callbacks.cpp │ └── standard_output_callbacks.h ├── command │ ├── commands.h │ ├── jscall.cpp │ ├── jsclear.cpp │ ├── jshelp.cpp │ ├── jslist.cpp │ ├── jsload.cpp │ ├── jsrun.cpp │ └── jsunload.cpp ├── core │ ├── js_pod.cpp │ └── js_pod.h ├── entrypoint.cpp ├── entrypoint.h ├── exports.def ├── extension.cpp ├── extension.h ├── git_version.h.in ├── main.cpp ├── precompile.h ├── script │ ├── dbgeng.js │ ├── jswd.js │ └── jswd │ │ ├── module.js │ │ ├── physical.js │ │ ├── processor.js │ │ ├── reader.js │ │ ├── register.js │ │ ├── segment.js │ │ ├── symbol.js │ │ ├── virtual.js │ │ └── writer.js ├── util │ ├── util_string.cpp │ └── util_string.h ├── version.h └── version.rc └── tests └── test.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Microsoft 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: None 7 | AlignConsecutiveMacros: None 8 | AlignConsecutiveAssignments: None 9 | AlignConsecutiveBitFields: None 10 | AlignConsecutiveDeclarations: None 11 | AlignEscapedNewlines: Right 12 | AlignOperands: Align 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortEnumsOnASingleLine: false 17 | AllowShortBlocksOnASingleLine: Never 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: None 20 | AllowShortLambdasOnASingleLine: All 21 | AllowShortIfStatementsOnASingleLine: Never 22 | AllowShortLoopsOnASingleLine: false 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: false 26 | AlwaysBreakTemplateDeclarations: MultiLine 27 | AttributeMacros: 28 | - __capability 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | BraceWrapping: 32 | AfterCaseLabel: false 33 | AfterClass: true 34 | AfterControlStatement: Always 35 | AfterEnum: true 36 | AfterFunction: true 37 | AfterNamespace: true 38 | AfterObjCDeclaration: true 39 | AfterStruct: true 40 | AfterUnion: false 41 | AfterExternBlock: true 42 | BeforeCatch: true 43 | BeforeElse: true 44 | BeforeLambdaBody: false 45 | BeforeWhile: false 46 | IndentBraces: false 47 | SplitEmptyFunction: true 48 | SplitEmptyRecord: true 49 | SplitEmptyNamespace: true 50 | BreakBeforeBinaryOperators: None 51 | BreakBeforeConceptDeclarations: true 52 | BreakBeforeBraces: Custom 53 | BreakBeforeInheritanceComma: false 54 | BreakInheritanceList: BeforeColon 55 | BreakBeforeTernaryOperators: true 56 | BreakConstructorInitializersBeforeComma: false 57 | BreakConstructorInitializers: BeforeColon 58 | BreakAfterJavaFieldAnnotations: false 59 | BreakStringLiterals: true 60 | ColumnLimit: 120 61 | CommentPragmas: '^ IWYU pragma:' 62 | QualifierAlignment: Leave 63 | CompactNamespaces: false 64 | ConstructorInitializerIndentWidth: 4 65 | ContinuationIndentWidth: 4 66 | Cpp11BracedListStyle: true 67 | DeriveLineEnding: true 68 | DerivePointerAlignment: false 69 | DisableFormat: false 70 | EmptyLineAfterAccessModifier: Never 71 | EmptyLineBeforeAccessModifier: LogicalBlock 72 | ExperimentalAutoDetectBinPacking: false 73 | PackConstructorInitializers: BinPack 74 | 75 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 76 | AllowAllConstructorInitializersOnNextLine: true 77 | FixNamespaceComments: true 78 | ForEachMacros: 79 | - foreach 80 | - Q_FOREACH 81 | - BOOST_FOREACH 82 | IfMacros: 83 | - KJ_IF_MAYBE 84 | IncludeBlocks: Preserve 85 | IncludeCategories: 86 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 87 | Priority: 2 88 | SortPriority: 0 89 | CaseSensitive: false 90 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 91 | Priority: 3 92 | SortPriority: 0 93 | CaseSensitive: false 94 | - Regex: '.*' 95 | Priority: 1 96 | SortPriority: 0 97 | CaseSensitive: false 98 | IncludeIsMainRegex: '(Test)?$' 99 | IncludeIsMainSourceRegex: '' 100 | IndentAccessModifiers: false 101 | IndentCaseLabels: false 102 | IndentCaseBlocks: false 103 | IndentGotoLabels: true 104 | IndentPPDirectives: None 105 | IndentExternBlock: AfterExternBlock 106 | IndentWidth: 4 107 | IndentWrappedFunctionNames: false 108 | InsertTrailingCommas: None 109 | JavaScriptQuotes: Leave 110 | JavaScriptWrapImports: true 111 | KeepEmptyLinesAtTheStartOfBlocks: true 112 | LambdaBodyIndentation: Signature 113 | MacroBlockBegin: '' 114 | MacroBlockEnd: '' 115 | MaxEmptyLinesToKeep: 1 116 | NamespaceIndentation: None 117 | ObjCBinPackProtocolList: Auto 118 | ObjCBlockIndentWidth: 2 119 | ObjCBreakBeforeNestedBlockParam: true 120 | ObjCSpaceAfterProperty: false 121 | ObjCSpaceBeforeProtocolList: true 122 | PenaltyBreakAssignment: 2 123 | PenaltyBreakBeforeFirstCallParameter: 19 124 | PenaltyBreakComment: 300 125 | PenaltyBreakFirstLessLess: 120 126 | PenaltyBreakOpenParenthesis: 0 127 | PenaltyBreakString: 1000 128 | PenaltyBreakTemplateDeclaration: 10 129 | PenaltyExcessCharacter: 1000000 130 | PenaltyReturnTypeOnItsOwnLine: 1000 131 | PenaltyIndentedWhitespace: 0 132 | PointerAlignment: Right 133 | PPIndentWidth: -1 134 | ReferenceAlignment: Pointer 135 | ReflowComments: true 136 | RemoveBracesLLVM: false 137 | SeparateDefinitionBlocks: Leave 138 | ShortNamespaceLines: 1 139 | SortIncludes: CaseSensitive 140 | SortJavaStaticImport: Before 141 | SortUsingDeclarations: true 142 | SpaceAfterCStyleCast: false 143 | SpaceAfterLogicalNot: false 144 | SpaceAfterTemplateKeyword: true 145 | SpaceBeforeAssignmentOperators: true 146 | SpaceBeforeCaseColon: false 147 | SpaceBeforeCpp11BracedList: false 148 | SpaceBeforeCtorInitializerColon: true 149 | SpaceBeforeInheritanceColon: true 150 | SpaceBeforeParens: ControlStatements 151 | SpaceBeforeParensOptions: 152 | AfterControlStatements: true 153 | AfterForeachMacros: true 154 | AfterFunctionDefinitionName: false 155 | AfterFunctionDeclarationName: false 156 | AfterIfMacros: true 157 | AfterOverloadedOperator: false 158 | BeforeNonEmptyParentheses: false 159 | SpaceAroundPointerQualifiers: Default 160 | SpaceBeforeRangeBasedForLoopColon: true 161 | SpaceInEmptyBlock: false 162 | SpaceInEmptyParentheses: false 163 | SpacesBeforeTrailingComments: 1 164 | SpacesInAngles: Never 165 | SpacesInConditionalStatement: false 166 | SpacesInContainerLiterals: true 167 | SpacesInCStyleCastParentheses: false 168 | SpacesInLineCommentPrefix: 169 | Minimum: 1 170 | Maximum: -1 171 | SpacesInParentheses: false 172 | SpacesInSquareBrackets: false 173 | SpaceBeforeSquareBrackets: false 174 | BitFieldColonSpacing: Both 175 | Standard: Latest 176 | StatementAttributeLikeMacros: 177 | - Q_EMIT 178 | StatementMacros: 179 | - Q_UNUSED 180 | - QT_REQUIRE_VERSION 181 | TabWidth: 4 182 | UseCRLF: false 183 | UseTab: Never 184 | WhitespaceSensitiveMacros: 185 | - STRINGIZE 186 | - PP_STRINGIZE 187 | - BOOST_PP_STRINGIZE 188 | - NS_SWIFT_NAME 189 | - CF_SWIFT_NAME 190 | ... 191 | 192 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: project 2 | 3 | on: push 4 | 5 | jobs: 6 | build-windows: 7 | runs-on: windows-latest 8 | steps: 9 | - name: checkout 10 | uses: actions/checkout@v2 11 | with: 12 | token: ${{ secrets.GIT_TOKEN }} 13 | 14 | - name: Get DateTime 15 | id: datetime 16 | run: | 17 | $datetime = Get-Date -Format "yyyyMMdd-HHmmss" 18 | echo "datetime=$datetime" >> $env:GITHUB_OUTPUT 19 | 20 | - name: Get Repository 21 | id: repository 22 | run: | 23 | $repository = Split-Path -Leaf $env:GITHUB_REPOSITORY 24 | echo "repository=$repository" >> $env:GITHUB_OUTPUT 25 | 26 | - name: Build x86 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GIT_TOKEN }} 29 | run: | 30 | mkdir build && cd build 31 | cmake -DCMAKE_BUILD_TYPE=Release -A Win32 -B "x86" .. 32 | cmake --build x86 --config Release 33 | 34 | - name: Build x64 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GIT_TOKEN }} 37 | run: | 38 | cd build 39 | cmake -DCMAKE_BUILD_TYPE=Release -A X64 -B "x64" .. 40 | cmake --build x64 --config Release 41 | 42 | - name: Create ZIP 43 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 44 | id: compress 45 | run: | 46 | $datetime = "${{steps.datetime.outputs.datetime}}" 47 | echo "[+] now is $datetime" 48 | Compress-Archive -Path "build\x86\Release\*.dll","build\x86\Release\*.pdb" -DestinationPath "${{ steps.repository.outputs.repository }}-${{ steps.datetime.outputs.datetime }}-x86.zip" 49 | Compress-Archive -Path "build\x64\Release\*.dll","build\x64\Release\*.pdb" -DestinationPath "${{ steps.repository.outputs.repository }}-${{ steps.datetime.outputs.datetime }}-x64.zip" 50 | 51 | - name: Create Release 52 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 53 | id: release 54 | uses: softprops/action-gh-release@v1 55 | with: 56 | tag_name: autotag-${{ steps.datetime.outputs.datetime }} 57 | generate_release_notes: true 58 | draft: false 59 | prerelease: false 60 | token: ${{ secrets.GIT_TOKEN }} 61 | files: | 62 | ${{ steps.repository.outputs.repository }}-${{ steps.datetime.outputs.datetime }}-x86.zip 63 | ${{ steps.repository.outputs.repository }}-${{ steps.datetime.outputs.datetime }}-x64.zip 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---> C++ 2 | # Prerequisites 3 | *.d 4 | 5 | # Compiled Object files 6 | *.slo 7 | *.lo 8 | *.o 9 | *.obj 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Fortran module files 21 | *.mod 22 | *.smod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | # ---> CMake 36 | CMakeLists.txt.user 37 | CMakeCache.txt 38 | CMakeFiles 39 | CMakeScripts 40 | Testing 41 | Makefile 42 | cmake_install.cmake 43 | install_manifest.txt 44 | compile_commands.json 45 | CTestTestfile.cmake 46 | _deps 47 | 48 | /cmake-build-debug 49 | /cmake-build-release 50 | /build 51 | /.xmake 52 | /gen 53 | /.idea 54 | /bin 55 | /.vs 56 | /out -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | project(jswd 4 | VERSION 1.0.0 5 | LANGUAGES C CXX 6 | ) 7 | 8 | if (UNIX AND CMAKE_COMPILER_IS_GNUCC) 9 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") 10 | endif () 11 | 12 | # =============================================================================================== 13 | # Library 14 | # =============================================================================================== 15 | 16 | option(BUILD_TESTS "build test code" OFF) 17 | 18 | if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) 19 | set(BUILD_TESTS ON) 20 | endif () 21 | 22 | file( 23 | GLOB_RECURSE 24 | SOURCES 25 | src/*.cpp 26 | src/*.c 27 | src/*.h 28 | ${PROJECT_BINARY_DIR}/gen/*.c 29 | ${PROJECT_BINARY_DIR}/gen/*.cpp 30 | ) 31 | 32 | file( 33 | GLOB_RECURSE 34 | HEADERS 35 | include/*.h 36 | ) 37 | 38 | # =============================================================================================== 39 | # jsex 40 | # =============================================================================================== 41 | set(JSEX_PATH $ENV{JSEX_PATH}) 42 | 43 | include(FetchContent) 44 | 45 | if (JSEX_PATH) 46 | 47 | option(USE_CHAKRA_CORE "use chackra core" OFF) 48 | 49 | add_subdirectory(${JSEX_PATH} ${PROJECT_BINARY_DIR}/jsex) 50 | 51 | get_target_property(JSEX_INCLUDES jsex INTERFACE_INCLUDE_DIRECTORIES) 52 | 53 | include_directories( 54 | ${JSEX_PATH}/include 55 | ${JSEX_INCLUDES} 56 | ) 57 | 58 | else () 59 | 60 | if(DEFINED ENV{GITHUB_TOKEN}) 61 | set(GIT_REPO https://tinysec:$ENV{GITHUB_TOKEN}@github.com/tinysec/jsex) 62 | else() 63 | set(GIT_REPO https://github.com/tinysec/jsex) 64 | endif() 65 | 66 | FetchContent_Declare(jsex 67 | GIT_REPOSITORY ${GIT_REPO} 68 | GIT_TAG autotag-20230627-075036 69 | ) 70 | 71 | FetchContent_MakeAvailable(jsex) 72 | endif () 73 | 74 | 75 | # =============================================================================================== 76 | # version 77 | # =============================================================================================== 78 | 79 | execute_process( 80 | COMMAND git rev-parse --abbrev-ref HEAD 81 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 82 | OUTPUT_VARIABLE GIT_BRANCH 83 | OUTPUT_STRIP_TRAILING_WHITESPACE 84 | ) 85 | execute_process( 86 | COMMAND git rev-parse --short HEAD 87 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 88 | OUTPUT_VARIABLE GIT_COMMIT_HASH 89 | OUTPUT_STRIP_TRAILING_WHITESPACE 90 | ) 91 | 92 | configure_file( 93 | "${CMAKE_CURRENT_SOURCE_DIR}/src/git_version.h.in" 94 | "${CMAKE_CURRENT_BINARY_DIR}/gen/git_version.h" 95 | ) 96 | 97 | 98 | # =============================================================================================== 99 | # executable 100 | # =============================================================================================== 101 | 102 | add_library( 103 | ${PROJECT_NAME} 104 | SHARED 105 | ${SOURCES} 106 | ${HEADERS} 107 | src/version.rc 108 | ) 109 | 110 | target_compile_definitions( 111 | ${PROJECT_NAME} 112 | PRIVATE 113 | BUILD_LIBRARY=1 114 | _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 115 | USE_EDGEMODE_JSRT 116 | ) 117 | 118 | set_target_properties(${PROJECT_NAME} PROPERTIES 119 | CXX_STANDARD 20 120 | CXX_STANDARD_REQUIRED ON 121 | C_STANDARD 11 122 | ) 123 | 124 | set_target_properties( 125 | ${PROJECT_NAME} PROPERTIES 126 | MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" 127 | ) 128 | 129 | set_target_properties( 130 | ${PROJECT_NAME} PROPERTIES 131 | OUTPUT_NAME "js" 132 | ) 133 | 134 | set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE) 135 | 136 | target_include_directories( 137 | ${PROJECT_NAME} 138 | PRIVATE 139 | ${CMAKE_CURRENT_SOURCE_DIR} 140 | ${CMAKE_CURRENT_SOURCE_DIR}/include 141 | ${CMAKE_CURRENT_SOURCE_DIR}/src 142 | ${CMAKE_CURRENT_SOURCE_DIR}/src/inc 143 | ${CMAKE_CURRENT_BINARY_DIR} 144 | ) 145 | 146 | target_link_libraries( 147 | ${PROJECT_NAME} 148 | PUBLIC 149 | jsex 150 | DbgEng 151 | ) 152 | 153 | target_sources( 154 | ${PROJECT_NAME} 155 | PRIVATE 156 | "${CMAKE_CURRENT_SOURCE_DIR}/src/exports.def" 157 | ) 158 | 159 | 160 | # =============================================================================================== 161 | # script 162 | # =============================================================================================== 163 | include(cmake/Binary2Header.cmake) 164 | 165 | 166 | 167 | bin2h( 168 | SOURCE_FILE "src/script/jswd.js" 169 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/jswd.js.h" 170 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_JSWD" 171 | ) 172 | 173 | bin2h( 174 | SOURCE_FILE "src/script/dbgeng.js" 175 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/dbgeng.js.h" 176 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_DBGENG" 177 | ) 178 | 179 | 180 | bin2h( 181 | SOURCE_FILE "src/script/jswd/module.js" 182 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/module.js.h" 183 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_MODULE" 184 | ) 185 | 186 | bin2h( 187 | SOURCE_FILE "src/script/jswd/physical.js" 188 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/physical.js.h" 189 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_PHYSICAL" 190 | ) 191 | 192 | bin2h( 193 | SOURCE_FILE "src/script/jswd/processor.js" 194 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/processor.js.h" 195 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_PROCESSOR" 196 | ) 197 | 198 | 199 | bin2h( 200 | SOURCE_FILE "src/script/jswd/reader.js" 201 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/reader.js.h" 202 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_READER" 203 | ) 204 | 205 | bin2h( 206 | SOURCE_FILE "src/script/jswd/register.js" 207 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/register.js.h" 208 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_REGISTER" 209 | ) 210 | 211 | bin2h( 212 | SOURCE_FILE "src/script/jswd/segment.js" 213 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/segment.js.h" 214 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_SEGMENT" 215 | ) 216 | 217 | 218 | bin2h( 219 | SOURCE_FILE "src/script/jswd/symbol.js" 220 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/symbol.js.h" 221 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_SYMBOL" 222 | ) 223 | 224 | 225 | bin2h( 226 | SOURCE_FILE "src/script/jswd/virtual.js" 227 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/virtual.js.h" 228 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_VIRTUAL" 229 | ) 230 | 231 | bin2h( 232 | SOURCE_FILE "src/script/jswd/writer.js" 233 | HEADER_FILE "${PROJECT_BINARY_DIR}/gen/script/writer.js.h" 234 | VARIABLE_NAME "JSWD_BUILTIN_SCRIPT_WRITER" 235 | ) 236 | 237 | 238 | # =============================================================================================== 239 | # test 240 | # =============================================================================================== 241 | 242 | if (BUILD_TESTS) 243 | 244 | include(CTest) 245 | 246 | add_executable( 247 | test_${PROJECT_NAME} 248 | ${SOURCES} 249 | ${HEADERS} 250 | tests/test.cpp 251 | ) 252 | 253 | # set lang requrired 254 | set_target_properties(test_${PROJECT_NAME} PROPERTIES 255 | CXX_STANDARD 20 256 | CXX_STANDARD_REQUIRED ON 257 | C_STANDARD 11 258 | ) 259 | 260 | set_target_properties( 261 | test_${PROJECT_NAME} PROPERTIES 262 | MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" 263 | ) 264 | 265 | 266 | target_link_libraries( 267 | test_${PROJECT_NAME} 268 | PUBLIC 269 | jsex 270 | DbgEng 271 | ) 272 | 273 | target_compile_definitions( 274 | test_${PROJECT_NAME} 275 | PRIVATE 276 | BUILD_TESTS=1 277 | _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 278 | USE_EDGEMODE_JSRT 279 | ) 280 | 281 | target_include_directories( 282 | test_${PROJECT_NAME} 283 | PRIVATE 284 | ${CMAKE_CURRENT_SOURCE_DIR} 285 | ${CMAKE_CURRENT_SOURCE_DIR}/include 286 | ${CMAKE_CURRENT_SOURCE_DIR}/src 287 | ${CMAKE_CURRENT_SOURCE_DIR}/src/inc 288 | ${CMAKE_CURRENT_BINARY_DIR} 289 | ) 290 | 291 | endif (BUILD_TESTS) 292 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jswd 2 | 3 | Windbg javascript extension for hacker , a gift from tinysec. 4 | 5 | That is refactored of the [JSRT](https://github.com/tinysec/jsrt) , using modern C++ and ES6 syntax. 6 | 7 | ## usage 8 | 9 | 1. download right arch version of zipped jswd file from github release. 10 | 11 | 2. decompress and put the 'js.dll' into same arch version windbg's extension dir. 12 | 13 | ![ext.png](assets/ext.png) 14 | 15 | 3. load the jswd by `.load js` 16 | 17 | ![help.png](assets/help.png) 18 | 19 | 4. have a nice day. 20 | -------------------------------------------------------------------------------- /assets/ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinysec/jswd/c72c60e6b97774391f756fe2f50e94e7c6c001d0/assets/ext.png -------------------------------------------------------------------------------- /assets/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinysec/jswd/c72c60e6b97774391f756fe2f50e94e7c6c001d0/assets/help.png -------------------------------------------------------------------------------- /cmake/Binary2Header.cmake: -------------------------------------------------------------------------------- 1 | include(CMakeParseArguments) 2 | 3 | # Function to wrap a given string into multiple lines at the given column position. 4 | # Parameters: 5 | # VARIABLE - The name of the CMake variable holding the string. 6 | # AT_COLUMN - The column position at which string will be wrapped. 7 | function(WRAP_STRING) 8 | set(oneValueArgs VARIABLE AT_COLUMN) 9 | cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) 10 | 11 | string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) 12 | math(EXPR offset "0") 13 | 14 | while (stringLength GREATER 0) 15 | 16 | if (stringLength GREATER ${WRAP_STRING_AT_COLUMN}) 17 | math(EXPR length "${WRAP_STRING_AT_COLUMN}") 18 | else () 19 | math(EXPR length "${stringLength}") 20 | endif () 21 | 22 | string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) 23 | set(lines "${lines}\n${line}") 24 | 25 | math(EXPR stringLength "${stringLength} - ${length}") 26 | math(EXPR offset "${offset} + ${length}") 27 | endwhile () 28 | 29 | set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) 30 | endfunction() 31 | 32 | # Function to embed contents of a file as byte array in C/C++ header file(.h). The header file 33 | # will contain a byte array and integer variable holding the size of the array. 34 | # Parameters 35 | # SOURCE_FILE - The path of source file whose contents will be embedded in the header file. 36 | # VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append 37 | # to this name and will be used a variable name for size variable. 38 | # HEADER_FILE - The path of header file. 39 | # APPEND - If specified appends to the header file instead of overwriting it 40 | # NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be 41 | # useful if the source file is a text file and we want to use the file contents 42 | # as string. But the size variable holds size of the byte array without this 43 | # null byte. 44 | # SKIP_LINES - Number of lines to skip (max 1). 45 | # Usage: 46 | # bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG") 47 | function(BIN2H) 48 | set(options APPEND NULL_TERMINATE RAW) 49 | set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE SKIP_LINES) 50 | cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN}) 51 | 52 | if (BIN2H_SKIP_LINES AND NOT BIN2H_SKIP_LINES EQUAL 1) 53 | message(AUTHOR_WARNING "Only 1 line skip is supported") 54 | endif () 55 | 56 | set(MSVC ON) 57 | # First workaround for MSVC limits (see below), generate data in hex: 58 | # cmake -DMSVC=ON Binary2Header.cmake... 59 | if (BIN2H_RAW AND NOT MSVC) 60 | file(READ ${BIN2H_SOURCE_FILE} string) 61 | if (BIN2H_SKIP_LINES) 62 | string(FIND "${string}" "\n" pos) 63 | math(EXPR pos "${pos}+1") 64 | string(SUBSTRING "${string}" ${pos} -1 string) 65 | endif () 66 | 67 | string(LENGTH "${string}" arraySize) 68 | if (MSVC) # TODO: Effectively deactivated by earlier NOT MSVC, still on brainstorming 69 | # Alternative workaround for MSVC limits to generate long string literals with concatenation: 70 | # - While an individual quoted string cannot be longer than 2048 bytes, 71 | # a string literal of roughly 65535 bytes can be constructed by concatenating strings. 72 | # - otherwise, compiler error C2026: string too big, trailing characters truncated 73 | # - 65K bytes of total length must not be exceeded. 74 | set(arrayValues "") 75 | foreach (_split_pos RANGE 0 ${arraySize} 2000) # Visual C++ max is 2048 bytes 76 | string(SUBSTRING "${string}" ${_split_pos} 2000 _concat_string) 77 | set(arrayValues "${arrayValues}R\"bin(${_concat_string})bin\"\n") 78 | unset(_concat_string) 79 | endforeach () 80 | else () 81 | set(arrayValues "R\"bin(${string})bin\"") 82 | endif () 83 | else () 84 | # reads source file contents as hex string 85 | file(READ ${BIN2H_SOURCE_FILE} hexString HEX) 86 | if (BIN2H_SKIP_LINES) 87 | string(FIND "${hexString}" "0a" pos) 88 | math(EXPR pos "${pos}+2") 89 | string(SUBSTRING ${hexString} ${pos} -1 hexString) 90 | endif () 91 | 92 | string(LENGTH ${hexString} hexStringLength) 93 | 94 | # appends null byte if asked 95 | if (BIN2H_NULL_TERMINATE) 96 | set(hexString "${hexString}00") 97 | endif () 98 | 99 | # wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line) 100 | wrap_string(VARIABLE hexString AT_COLUMN 32) 101 | math(EXPR arraySize "${hexStringLength} / 2") 102 | 103 | # adds '0x' prefix and comma suffix before and after every byte respectively 104 | string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString}) 105 | # remove trailing spaces 106 | string(REGEX REPLACE " \n" "\n" arrayValues ${arrayValues}) 107 | # removes trailing comma 108 | string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) 109 | set(arrayValues "{${arrayValues}}") 110 | endif () 111 | 112 | # converts the variable name into proper C identifier 113 | if (NOT BIN2H_VARIABLE_NAME) 114 | set(BIN2H_VARIABLE_NAME "${BIN2H_SOURCE_FILE}") 115 | endif () 116 | string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) 117 | #string(TOLOWER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) 118 | 119 | # declares byte array and the length variables 120 | set(fileGuardBegin "#ifndef ${BIN2H_VARIABLE_NAME}_HEADER_FILE\n#define ${BIN2H_VARIABLE_NAME}_HEADER_FILE\n") 121 | set(fileGuardEnd "#endif // ${BIN2H_VARIABLE_NAME}_HEADER_FILE\n\n") 122 | 123 | set(arraySizeDefinition "#define SIZEOF_${BIN2H_VARIABLE_NAME} ${arraySize}") 124 | 125 | set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[ SIZEOF_${BIN2H_VARIABLE_NAME} ] = ${arrayValues};") 126 | 127 | 128 | set(declarations "${fileGuardBegin}\n\n${arraySizeDefinition}\n\n${arrayDefinition}\n\n${fileGuardEnd}\n") 129 | if (BIN2H_APPEND) 130 | file(APPEND ${BIN2H_HEADER_FILE} "${declarations}") 131 | else () 132 | file(WRITE ${BIN2H_HEADER_FILE} "${declarations}") 133 | endif () 134 | endfunction() 135 | 136 | if (CMAKE_SCRIPT_MODE_FILE AND "${CMAKE_SCRIPT_MODE_FILE}" MATCHES "Binary2Header.cmake$") 137 | # Parse command line argmuents 138 | set(ARG_NUM 1) 139 | set(conversion_type "HEADER") 140 | set(options "") 141 | while (ARG_NUM LESS CMAKE_ARGC) 142 | set(CURRENT_ARG ${CMAKE_ARGV${ARG_NUM}}) 143 | if (${CURRENT_ARG} MATCHES "^--usage$") 144 | message("Usage: 145 | cmake -P cmake/Binary2Header.cmake [options] infile outfile 146 | Options: 147 | --header convert to a header file 148 | --locales convert locales json files to a header file 149 | --variable-name [NAME] variable name, default is converted to C identifier 150 | --skip-line [NUM] skip NUM lines, default 0 151 | --append append to a file 152 | --raw generate raw string literals 153 | --null add a null byte(zero) to the byte array") 154 | set(exit TRUE) 155 | elseif (${CURRENT_ARG} MATCHES "^--header") 156 | set(conversion_type "HEADER") 157 | elseif (${CURRENT_ARG} MATCHES "--locales") 158 | set(conversion_type "LOCALES") 159 | elseif (${CURRENT_ARG} MATCHES "^--append$") 160 | list(APPEND options "APPEND") 161 | elseif (${CURRENT_ARG} MATCHES "^--raw") 162 | list(APPEND options "RAW") 163 | elseif (${CURRENT_ARG} MATCHES "^--null$") 164 | list(APPEND options "NULL_TERMINATE") 165 | elseif (${CURRENT_ARG} MATCHES "^--variable-name$") 166 | math(EXPR ARG_NUM "${ARG_NUM}+1") 167 | list(APPEND options "VARIABLE_NAME;${CMAKE_ARGV${ARG_NUM}}") 168 | elseif (${CURRENT_ARG} MATCHES "^--skip$") 169 | math(EXPR ARG_NUM "${ARG_NUM}+1") 170 | list(APPEND options "SKIP_LINES;${CMAKE_ARGV${ARG_NUM}}") 171 | elseif (${CURRENT_ARG} MATCHES "^-P") 172 | math(EXPR ARG_NUM "${ARG_NUM}+1") # skip -P and self 173 | elseif (${CURRENT_ARG} MATCHES "^-D") 174 | set(_) # skip self and any -D variables 175 | elseif (${CURRENT_ARG} MATCHES "^[^-]") 176 | if (NOT source) 177 | set(source ${CURRENT_ARG}) 178 | elseif (NOT target) 179 | set(target ${CURRENT_ARG}) 180 | endif () 181 | endif () 182 | math(EXPR ARG_NUM "${ARG_NUM}+1") 183 | endwhile () 184 | 185 | if (NOT exit) 186 | if (NOT source OR NOT EXISTS ${source}) 187 | message(FATAL_ERROR "no source file or ${source} does not exist") 188 | elseif (NOT target) 189 | message(FATAL_ERROR "no target file") 190 | endif () 191 | 192 | if (conversion_type MATCHES HEADER) 193 | bin2h(SOURCE_FILE ${source} HEADER_FILE ${target} ${options}) 194 | elseif (conversion_type MATCHES LOCALES) 195 | file(WRITE ${target} "#include \n") 196 | file(GLOB json_files LIST_DIRECTORIES FALSE "${source}/*.json") 197 | foreach (file ${json_files}) 198 | get_filename_component(name "${file}" NAME) 199 | bin2h(SOURCE_FILE ${file} HEADER_FILE ${target} VARIABLE_NAME ${name} APPEND RAW) 200 | endforeach () 201 | 202 | set(map "\nconst std::unordered_map locales_json = {\n") 203 | foreach (file ${json_files}) 204 | get_filename_component(name "${file}" NAME) 205 | get_filename_component(locale "${file}" NAME_WE) 206 | string(MAKE_C_IDENTIFIER "${name}" name) 207 | string(TOLOWER "${name}" name) 208 | set(map "${map} {\"${locale}\", {${name}, ${name} + ${name}_len}},\n") 209 | endforeach () 210 | set(map "${map}};\n") 211 | file(APPEND ${target} "${map}") 212 | endif () 213 | endif () 214 | endif () 215 | -------------------------------------------------------------------------------- /jstests/test.js: -------------------------------------------------------------------------------- 1 | 2 | const assert = require("assert"); 3 | 4 | const jswd = require("jswd"); 5 | 6 | const dbgeng = require("dbgeng"); 7 | 8 | const fmt = require("fmt"); 9 | 10 | const typing = require("typing"); 11 | 12 | 13 | function main(argv) 14 | { 15 | fmt.printf( jswd.fieldOffset('_UNICODE_STRING' , 'Buffer') ); 16 | 17 | 18 | return 0; 19 | } 20 | exports.main = main; 21 | 22 | -------------------------------------------------------------------------------- /src/binding/dbgeng/binding_client.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file binding_client.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include 10 | 11 | #include "binding_dbgeng.h" 12 | 13 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetExitCode( 14 | 15 | _In_ JsValueRef callee, 16 | 17 | _In_ bool isConstructCall, 18 | 19 | _In_ JsValueRef *arguments, 20 | 21 | _In_ unsigned short argumentCount, 22 | 23 | _In_opt_ void *callbackState 24 | ) 25 | { 26 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 27 | 28 | JsValueRef result = nullptr; 29 | 30 | JsErrorCode errorCode = JsErrorFatal; 31 | 32 | HRESULT hr = E_FAIL; 33 | 34 | ULONG code = 0; 35 | 36 | do 37 | { 38 | hr = pthis->m_debugClient->GetExitCode(&code); 39 | if ( !SUCCEEDED(hr) ) 40 | { 41 | JsExThrowError("GetExitCode fail 0x%08X" , hr); 42 | break; 43 | } 44 | 45 | JsIntToNumber( (int)code , &result ); 46 | 47 | } while (false); 48 | 49 | return result; 50 | } 51 | 52 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetIdentity( 53 | 54 | _In_ JsValueRef callee, 55 | 56 | _In_ bool isConstructCall, 57 | 58 | _In_ JsValueRef *arguments, 59 | 60 | _In_ unsigned short argumentCount, 61 | 62 | _In_opt_ void *callbackState 63 | ) 64 | { 65 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 66 | 67 | JsValueRef result = nullptr; 68 | 69 | JsErrorCode errorCode = JsErrorFatal; 70 | 71 | HRESULT hr = E_FAIL; 72 | 73 | ULONG bufferSize = 0; 74 | 75 | ULONG dataSize = 0; 76 | 77 | std::vector buffer; 78 | 79 | do 80 | { 81 | if (argumentCount < 1) 82 | { 83 | JsExThrowError("invalid argument count %d" , argumentCount); 84 | break; 85 | } 86 | 87 | hr = pthis->m_debugClient->GetIdentity(nullptr , 0 , &bufferSize ); 88 | 89 | if ( 0 == bufferSize ) 90 | { 91 | JsExThrowError("GetIdentity fail 0x%08X" , hr); 92 | break; 93 | } 94 | 95 | buffer.resize( bufferSize ); 96 | 97 | hr = pthis->m_debugClient->GetIdentity( buffer.data() , bufferSize , &dataSize ); 98 | if ( !SUCCEEDED(hr) ) 99 | { 100 | JsExThrowError("GetIdentity fail 0x%08X" , hr); 101 | break; 102 | } 103 | 104 | JsExCreateString( buffer.data() , dataSize , &result ); 105 | 106 | } while (false); 107 | 108 | return result; 109 | } 110 | 111 | // This method is available only for live user-mode debugging 112 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetRunningProcessDescription( 113 | 114 | _In_ JsValueRef callee, 115 | 116 | _In_ bool isConstructCall, 117 | 118 | _In_ JsValueRef *arguments, 119 | 120 | _In_ unsigned short argumentCount, 121 | 122 | _In_opt_ void *callbackState 123 | ) 124 | { 125 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 126 | 127 | JsValueRef result = nullptr; 128 | 129 | JsErrorCode errorCode = JsErrorFatal; 130 | 131 | HRESULT hr = E_FAIL; 132 | 133 | uint64_t arg1Server = 0; 134 | 135 | uint32_t arg2SystemId = 0; 136 | 137 | uint32_t arg3Flags = 0; 138 | 139 | std::vector exeName; 140 | 141 | ULONG exeNameBufferSize = 0; 142 | 143 | ULONG exeNameDataSize = 0; 144 | 145 | std::vector description; 146 | 147 | ULONG descriptionBufferSize = 0; 148 | 149 | ULONG descriptionDataSize = 0; 150 | 151 | JsValueRef info = nullptr; 152 | 153 | do 154 | { 155 | if (argumentCount < 4) 156 | { 157 | JsExThrowError("invalid argument count %d" , argumentCount); 158 | break; 159 | } 160 | 161 | errorCode = JsExAssumeUint64( arguments[1] , &arg1Server ); 162 | if (JsNoError != errorCode) 163 | { 164 | JsExThrowError("assume server fail 0x%08X" , errorCode); 165 | break; 166 | } 167 | 168 | errorCode = JsExAssumeUint32( arguments[2] , &arg2SystemId ); 169 | if (JsNoError != errorCode) 170 | { 171 | JsExThrowError("assume systemId fail 0x%08X" , errorCode); 172 | break; 173 | } 174 | 175 | errorCode = JsExAssumeUint32( arguments[3] , &arg3Flags ); 176 | if (JsNoError != errorCode) 177 | { 178 | JsExThrowError("assume flags fail 0x%08X" , errorCode); 179 | break; 180 | } 181 | 182 | pthis->m_debugClient->GetRunningProcessDescription( 183 | arg1Server , 184 | arg2SystemId , 185 | arg3Flags , 186 | nullptr , 187 | 0, 188 | &exeNameBufferSize, 189 | nullptr , 190 | 0, 191 | &descriptionBufferSize 192 | ); 193 | 194 | if ( 0 != exeNameBufferSize ) 195 | { 196 | exeName.resize( exeNameBufferSize ); 197 | } 198 | 199 | if ( 0 != descriptionBufferSize ) 200 | { 201 | description.resize( descriptionBufferSize ); 202 | } 203 | 204 | hr = pthis->m_debugClient->GetRunningProcessDescription( 205 | arg1Server , 206 | arg2SystemId , 207 | arg3Flags , 208 | exeName.data() , 209 | exeNameBufferSize, 210 | &exeNameDataSize, 211 | description.data() , 212 | descriptionBufferSize, 213 | &descriptionDataSize 214 | ); 215 | 216 | if ( !SUCCEEDED(hr) ) 217 | { 218 | JsExThrowError("GetRunningProcessDescription fail 0x%08X" , hr); 219 | break; 220 | } 221 | 222 | errorCode = JsCreateObject( &info ); 223 | if (JsNoError != errorCode) 224 | { 225 | JsExThrowError("JsCreateObject 0x%08X" , errorCode); 226 | break; 227 | } 228 | 229 | if ( exeNameDataSize > 1 ) 230 | { 231 | errorCode = JsExSetPropertyString( info , "exeName" , std::string( exeName.data() , exeNameDataSize - 1) , true); 232 | if (JsNoError != errorCode) 233 | { 234 | JsExThrowError("JsExSetPropertyString 0x%08X" , errorCode); 235 | break; 236 | } 237 | } 238 | else 239 | { 240 | errorCode = JsExSetPropertyString( info , "exeName" , "" , true); 241 | if (JsNoError != errorCode) 242 | { 243 | JsExThrowError("JsExSetPropertyString 0x%08X" , errorCode); 244 | break; 245 | } 246 | } 247 | 248 | if ( descriptionDataSize > 1 ) 249 | { 250 | errorCode = JsExSetPropertyString( info , "description" , std::string( description.data() , descriptionDataSize - 1) , true); 251 | if (JsNoError != errorCode) 252 | { 253 | JsExThrowError("JsExSetPropertyString 0x%08X" , errorCode); 254 | break; 255 | } 256 | } 257 | else 258 | { 259 | errorCode = JsExSetPropertyString( info , "description" , "", true); 260 | if (JsNoError != errorCode) 261 | { 262 | JsExThrowError("JsExSetPropertyString 0x%08X" , errorCode); 263 | break; 264 | } 265 | } 266 | result = info; 267 | 268 | } while (false); 269 | 270 | return result; 271 | } 272 | 273 | // This method is available only for live user-mode debugging. 274 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetRunningProcessSystemIdByExecutableName( 275 | 276 | _In_ JsValueRef callee, 277 | 278 | _In_ bool isConstructCall, 279 | 280 | _In_ JsValueRef *arguments, 281 | 282 | _In_ unsigned short argumentCount, 283 | 284 | _In_opt_ void *callbackState 285 | ) 286 | { 287 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 288 | 289 | JsValueRef result = nullptr; 290 | 291 | JsErrorCode errorCode = JsErrorFatal; 292 | 293 | HRESULT hr = E_FAIL; 294 | 295 | uint64_t arg1Server = 0; 296 | 297 | std::string arg2ExeName; 298 | 299 | uint32_t arg3Flags = 0; 300 | 301 | ULONG id = 0; 302 | 303 | do 304 | { 305 | if (argumentCount < 4) 306 | { 307 | JsExThrowError("invalid argument count %d" , argumentCount); 308 | break; 309 | } 310 | 311 | errorCode = JsExAssumeUint64( arguments[1] , &arg1Server ); 312 | if (JsNoError != errorCode) 313 | { 314 | JsExThrowError("assume server fail 0x%08X" , errorCode); 315 | break; 316 | } 317 | 318 | errorCode = JsExAssumeString( arguments[2] , true , &arg2ExeName ); 319 | if (JsNoError != errorCode) 320 | { 321 | JsExThrowError("assume exeName fail 0x%08X" , errorCode); 322 | break; 323 | } 324 | 325 | errorCode = JsExAssumeUint32( arguments[3] , &arg3Flags ); 326 | if (JsNoError != errorCode) 327 | { 328 | JsExThrowError("assume flags fail 0x%08X" , errorCode); 329 | break; 330 | } 331 | 332 | hr = pthis->m_debugClient->GetRunningProcessSystemIdByExecutableName( 333 | arg1Server , 334 | arg2ExeName.c_str(), 335 | arg3Flags , 336 | &id 337 | ); 338 | if ( !SUCCEEDED(hr) ) 339 | { 340 | JsExThrowError("GetRunningProcessSystemIdByExecutableName fail 0x%08X" , hr); 341 | break; 342 | } 343 | 344 | JsIntToNumber( (int)id , &result ); 345 | 346 | } while (false); 347 | 348 | return result; 349 | } 350 | 351 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::WriteDumpFile( 352 | 353 | _In_ JsValueRef callee, 354 | 355 | _In_ bool isConstructCall, 356 | 357 | _In_ JsValueRef *arguments, 358 | 359 | _In_ unsigned short argumentCount, 360 | 361 | _In_opt_ void *callbackState 362 | ) 363 | { 364 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 365 | 366 | JsValueRef result = nullptr; 367 | 368 | JsErrorCode errorCode = JsErrorFatal; 369 | 370 | HRESULT hr = E_FAIL; 371 | 372 | std::string arg1FileName; 373 | 374 | uint32_t arg2Qualifier = 0; 375 | 376 | do 377 | { 378 | if (argumentCount < 3) 379 | { 380 | JsExThrowError("invalid argument count %d" , argumentCount); 381 | break; 382 | } 383 | 384 | errorCode = JsExAssumeString( arguments[1] , true , &arg1FileName ); 385 | if (JsNoError != errorCode) 386 | { 387 | JsExThrowError("assume filename fail 0x%08X" , errorCode); 388 | break; 389 | } 390 | 391 | errorCode = JsExAssumeUint32( arguments[2] , &arg2Qualifier ); 392 | if (JsNoError != errorCode) 393 | { 394 | JsExThrowError("assume qualifier fail 0x%08X" , errorCode); 395 | break; 396 | } 397 | 398 | hr = pthis->m_debugClient->WriteDumpFile( 399 | arg1FileName.c_str() , 400 | arg2Qualifier 401 | ); 402 | 403 | if ( !SUCCEEDED(hr) ) 404 | { 405 | JsBoolToBoolean( false , &result); 406 | break; 407 | } 408 | 409 | JsBoolToBoolean( true , &result); 410 | 411 | } while (false); 412 | 413 | return result; 414 | } 415 | -------------------------------------------------------------------------------- /src/binding/dbgeng/binding_client2.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file binding_client2.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include 10 | 11 | #include "binding_dbgeng.h" 12 | 13 | 14 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::IsKernelDebuggerEnabled( 15 | 16 | _In_ JsValueRef callee, 17 | 18 | _In_ bool isConstructCall, 19 | 20 | _In_ JsValueRef *arguments, 21 | 22 | _In_ unsigned short argumentCount, 23 | 24 | _In_opt_ void *callbackState 25 | ) 26 | { 27 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 28 | 29 | JsValueRef result = nullptr; 30 | 31 | JsErrorCode errorCode = JsErrorFatal; 32 | 33 | HRESULT hr = E_FAIL; 34 | 35 | do 36 | { 37 | hr = pthis->m_debugClient2->IsKernelDebuggerEnabled(); 38 | if ( SUCCEEDED(hr) ) 39 | { 40 | JsBoolToBoolean(true , &result ); 41 | } 42 | else 43 | { 44 | JsBoolToBoolean(false , &result ); 45 | } 46 | 47 | } while (false); 48 | 49 | return result; 50 | } 51 | -------------------------------------------------------------------------------- /src/binding/dbgeng/binding_dbgeng.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file binding_dbgeng.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "binding_dbgeng.h" 10 | 11 | BindingDbgEng::BindingDbgEng(IDebugClient *debugClient, IDebugControl *debugControl) 12 | { 13 | this->m_handle = nullptr; 14 | 15 | this->m_debugClient = debugClient; 16 | 17 | this->m_debugClient2 = nullptr; 18 | 19 | this->m_debugControl = debugControl; 20 | 21 | this->m_debugDataSpaces = nullptr; 22 | 23 | this->m_debugRegisters = nullptr; 24 | 25 | this->m_debugSymbols = nullptr; 26 | 27 | this->m_debugSystemObjects = nullptr; 28 | 29 | this->m_debugSystemObjects2 = nullptr; 30 | } 31 | 32 | BindingDbgEng::~BindingDbgEng() 33 | { 34 | if (nullptr != this->m_debugClient2) 35 | { 36 | this->m_debugClient2->Release(); 37 | this->m_debugClient2 = nullptr; 38 | } 39 | 40 | if (nullptr != this->m_debugDataSpaces) 41 | { 42 | this->m_debugDataSpaces->Release(); 43 | this->m_debugDataSpaces = nullptr; 44 | } 45 | 46 | if (nullptr != this->m_debugRegisters) 47 | { 48 | this->m_debugRegisters->Release(); 49 | this->m_debugRegisters = nullptr; 50 | } 51 | 52 | if (nullptr != this->m_debugSymbols) 53 | { 54 | this->m_debugSymbols->Release(); 55 | this->m_debugSymbols = nullptr; 56 | } 57 | 58 | if (nullptr != this->m_debugSystemObjects) 59 | { 60 | this->m_debugSystemObjects->Release(); 61 | this->m_debugSystemObjects = nullptr; 62 | } 63 | 64 | if (nullptr != this->m_debugSystemObjects2) 65 | { 66 | this->m_debugSystemObjects2->Release(); 67 | this->m_debugSystemObjects2 = nullptr; 68 | } 69 | } 70 | 71 | JsErrorCode BindingDbgEng::Initialize() 72 | { 73 | JsErrorCode errorCode = JsErrorFatal; 74 | 75 | JsErrorCode finalCode = JsErrorFatal; 76 | 77 | HRESULT hr = E_FAIL; 78 | 79 | do 80 | { 81 | hr = this->m_debugClient->QueryInterface( __uuidof(IDebugDataSpaces), (PVOID *)&(this->m_debugDataSpaces) ); 82 | if ( !SUCCEEDED(hr) ) 83 | { 84 | break ; 85 | } 86 | 87 | hr = this->m_debugClient->QueryInterface( __uuidof(IDebugClient2), (PVOID *)&(this->m_debugClient2) ); 88 | if ( !SUCCEEDED(hr) ) 89 | { 90 | break ; 91 | } 92 | 93 | hr = this->m_debugClient->QueryInterface( __uuidof(IDebugDataSpaces), (PVOID *)&(this->m_debugDataSpaces) ); 94 | if ( !SUCCEEDED(hr) ) 95 | { 96 | break ; 97 | } 98 | 99 | hr = this->m_debugClient->QueryInterface( __uuidof(IDebugRegisters), (PVOID *)&(this->m_debugRegisters) ); 100 | if ( !SUCCEEDED(hr) ) 101 | { 102 | break ; 103 | } 104 | 105 | hr = this->m_debugClient->QueryInterface( __uuidof(IDebugSymbols), (PVOID *)&(this->m_debugSymbols) ); 106 | if ( !SUCCEEDED(hr) ) 107 | { 108 | break ; 109 | } 110 | 111 | hr = this->m_debugClient->QueryInterface( __uuidof(IDebugSystemObjects), (PVOID *)&(this->m_debugSystemObjects) ); 112 | if ( !SUCCEEDED(hr) ) 113 | { 114 | break ; 115 | } 116 | 117 | hr = this->m_debugClient->QueryInterface( __uuidof(IDebugSystemObjects2), (PVOID *)&(this->m_debugSystemObjects2) ); 118 | if ( !SUCCEEDED(hr) ) 119 | { 120 | break ; 121 | } 122 | 123 | 124 | errorCode = JsCreateExternalObject(this, nullptr, &(this->m_handle)); 125 | if (JsNoError != errorCode) 126 | { 127 | break; 128 | } 129 | 130 | // bind 131 | errorCode = this->bindDebugClient(); 132 | if (JsNoError != errorCode) 133 | { 134 | finalCode = errorCode; 135 | break; 136 | } 137 | 138 | errorCode = this->bindDebugClient2(); 139 | if (JsNoError != errorCode) 140 | { 141 | finalCode = errorCode; 142 | break; 143 | } 144 | 145 | errorCode = this->bindDebugControl(); 146 | if (JsNoError != errorCode) 147 | { 148 | finalCode = errorCode; 149 | break; 150 | } 151 | 152 | errorCode = this->bindDebugDataSpaces(); 153 | if (JsNoError != errorCode) 154 | { 155 | finalCode = errorCode; 156 | break; 157 | } 158 | 159 | errorCode = this->bindDebugRegisters(); 160 | if (JsNoError != errorCode) 161 | { 162 | finalCode = errorCode; 163 | break; 164 | } 165 | 166 | errorCode = this->bindDebugSymbols(); 167 | if (JsNoError != errorCode) 168 | { 169 | finalCode = errorCode; 170 | break; 171 | } 172 | 173 | errorCode = this->bindDebugSystemObjects(); 174 | if (JsNoError != errorCode) 175 | { 176 | finalCode = errorCode; 177 | break; 178 | } 179 | 180 | errorCode = this->bindDebugSystemObjects2(); 181 | if (JsNoError != errorCode) 182 | { 183 | finalCode = errorCode; 184 | break; 185 | } 186 | 187 | finalCode = JsNoError; 188 | 189 | } while (false); 190 | 191 | return finalCode; 192 | } 193 | 194 | JsValueRef BindingDbgEng::GetHandle() 195 | { 196 | return this->m_handle; 197 | } 198 | 199 | JsErrorCode BindingDbgEng::bindRoutine( 200 | _In_ const std::string &name, 201 | _In_ JsNativeFunction routine 202 | ) 203 | { 204 | return JsExSetPropertyFunction(this->m_handle, name, routine,this, true); 205 | } 206 | 207 | JsErrorCode BindingDbgEng::bindDebugClient() 208 | { 209 | JsErrorCode errorCode = JsErrorFatal; 210 | 211 | JsErrorCode finalCode = JsErrorFatal; 212 | 213 | do 214 | { 215 | 216 | errorCode = this->bindRoutine("getExitCode", BindingDbgEng::GetExitCode); 217 | if (JsNoError != errorCode) 218 | { 219 | break; 220 | } 221 | 222 | errorCode = this->bindRoutine("getIdentity", BindingDbgEng::GetIdentity); 223 | if (JsNoError != errorCode) 224 | { 225 | break; 226 | } 227 | 228 | errorCode = this->bindRoutine("getRunningProcessDescription", BindingDbgEng::GetRunningProcessDescription); 229 | if (JsNoError != errorCode) 230 | { 231 | break; 232 | } 233 | 234 | errorCode = this->bindRoutine("getRunningProcessSystemIdByExecutableName", BindingDbgEng::GetRunningProcessSystemIdByExecutableName); 235 | if (JsNoError != errorCode) 236 | { 237 | break; 238 | } 239 | 240 | errorCode = this->bindRoutine("writeDumpFile", BindingDbgEng::WriteDumpFile); 241 | if (JsNoError != errorCode) 242 | { 243 | break; 244 | } 245 | 246 | finalCode = JsNoError; 247 | } while (false); 248 | 249 | return finalCode; 250 | } 251 | 252 | JsErrorCode BindingDbgEng::bindDebugClient2() 253 | { 254 | JsErrorCode errorCode = JsErrorFatal; 255 | 256 | JsErrorCode finalCode = JsErrorFatal; 257 | 258 | do 259 | { 260 | 261 | errorCode = this->bindRoutine("isKernelDebuggerEnabled", BindingDbgEng::IsKernelDebuggerEnabled); 262 | if (JsNoError != errorCode) 263 | { 264 | break; 265 | } 266 | 267 | finalCode = JsNoError; 268 | } while (false); 269 | 270 | return finalCode; 271 | } 272 | 273 | JsErrorCode BindingDbgEng::bindDebugControl() 274 | { 275 | JsErrorCode errorCode = JsErrorFatal; 276 | 277 | JsErrorCode finalCode = JsErrorFatal; 278 | 279 | do 280 | { 281 | 282 | errorCode = this->bindRoutine("assemble", BindingDbgEng::Assemble); 283 | if (JsNoError != errorCode) 284 | { 285 | break; 286 | } 287 | 288 | errorCode = this->bindRoutine("callExtension", BindingDbgEng::CallExtension); 289 | if (JsNoError != errorCode) 290 | { 291 | break; 292 | } 293 | 294 | errorCode = this->bindRoutine("disassemble", BindingDbgEng::Disassemble); 295 | if (JsNoError != errorCode) 296 | { 297 | break; 298 | } 299 | 300 | errorCode = this->bindRoutine("execute", BindingDbgEng::Execute); 301 | if (JsNoError != errorCode) 302 | { 303 | break; 304 | } 305 | 306 | errorCode = this->bindRoutine("getActualProcessorType", BindingDbgEng::GetActualProcessorType); 307 | if (JsNoError != errorCode) 308 | { 309 | break; 310 | } 311 | 312 | errorCode = this->bindRoutine("getCodeLevel", BindingDbgEng::GetCodeLevel); 313 | if (JsNoError != errorCode) 314 | { 315 | break; 316 | } 317 | 318 | errorCode = this->bindRoutine("getDebuggeeType", BindingDbgEng::GetDebuggeeType); 319 | if (JsNoError != errorCode) 320 | { 321 | break; 322 | } 323 | 324 | errorCode = this->bindRoutine("getEffectiveProcessorType", BindingDbgEng::GetEffectiveProcessorType); 325 | if (JsNoError != errorCode) 326 | { 327 | break; 328 | } 329 | 330 | errorCode = this->bindRoutine("getExecutingProcessorType", BindingDbgEng::GetExecutingProcessorType); 331 | if (JsNoError != errorCode) 332 | { 333 | break; 334 | } 335 | 336 | errorCode = this->bindRoutine("getExecutionStatus", BindingDbgEng::GetExecutionStatus); 337 | if (JsNoError != errorCode) 338 | { 339 | break; 340 | } 341 | 342 | errorCode = this->bindRoutine("getNearInstruction", BindingDbgEng::GetNearInstruction); 343 | if (JsNoError != errorCode) 344 | { 345 | break; 346 | } 347 | 348 | errorCode = this->bindRoutine("getNumberPossibleExecutingProcessorTypes", BindingDbgEng::GetNumberPossibleExecutingProcessorTypes); 349 | if (JsNoError != errorCode) 350 | { 351 | break; 352 | } 353 | 354 | errorCode = this->bindRoutine("getNumberProcessors", BindingDbgEng::GetNumberProcessors); 355 | if (JsNoError != errorCode) 356 | { 357 | break; 358 | } 359 | 360 | errorCode = this->bindRoutine("getNumberSupportedProcessorTypes", BindingDbgEng::GetNumberSupportedProcessorTypes); 361 | if (JsNoError != errorCode) 362 | { 363 | break; 364 | } 365 | 366 | errorCode = this->bindRoutine("getPageSize", BindingDbgEng::GetPageSize); 367 | if (JsNoError != errorCode) 368 | { 369 | break; 370 | } 371 | 372 | 373 | errorCode = this->bindRoutine("getProcessorTypeNames", BindingDbgEng::GetProcessorTypeNames); 374 | if (JsNoError != errorCode) 375 | { 376 | break; 377 | } 378 | 379 | errorCode = this->bindRoutine("getReturnOffset", BindingDbgEng::GetReturnOffset); 380 | if (JsNoError != errorCode) 381 | { 382 | break; 383 | } 384 | 385 | errorCode = this->bindRoutine("getStackTrace", BindingDbgEng::GetStackTrace); 386 | if (JsNoError != errorCode) 387 | { 388 | break; 389 | } 390 | 391 | errorCode = this->bindRoutine("getSystemVersion", BindingDbgEng::GetSystemVersion); 392 | if (JsNoError != errorCode) 393 | { 394 | break; 395 | } 396 | 397 | errorCode = this->bindRoutine("isPointer64Bit", BindingDbgEng::IsPointer64Bit); 398 | if (JsNoError != errorCode) 399 | { 400 | break; 401 | } 402 | 403 | errorCode = this->bindRoutine("readBugCheck", BindingDbgEng::ReadBugCheck); 404 | if (JsNoError != errorCode) 405 | { 406 | break; 407 | } 408 | 409 | 410 | errorCode = this->bindRoutine("setEffectiveProcessorType", BindingDbgEng::SetEffectiveProcessorType); 411 | if (JsNoError != errorCode) 412 | { 413 | break; 414 | } 415 | 416 | errorCode = this->bindRoutine("setExecutionStatus", BindingDbgEng::SetExecutionStatus); 417 | if (JsNoError != errorCode) 418 | { 419 | break; 420 | } 421 | 422 | finalCode = JsNoError; 423 | } while (false); 424 | 425 | return finalCode; 426 | } 427 | 428 | JsErrorCode BindingDbgEng::bindDebugDataSpaces() 429 | { 430 | JsErrorCode errorCode = JsErrorFatal; 431 | 432 | JsErrorCode finalCode = JsErrorFatal; 433 | 434 | do 435 | { 436 | 437 | errorCode = this->bindRoutine("readBus", BindingDbgEng::ReadBus); 438 | if (JsNoError != errorCode) 439 | { 440 | break; 441 | } 442 | 443 | errorCode = this->bindRoutine("readControl" , BindingDbgEng::ReadControl ); 444 | if (JsNoError != errorCode) 445 | { 446 | break; 447 | } 448 | 449 | errorCode = this->bindRoutine("readDebugger", BindingDbgEng::ReadDebugger); 450 | if (JsNoError != errorCode) 451 | { 452 | break; 453 | } 454 | 455 | errorCode = this->bindRoutine("readIo" , BindingDbgEng::ReadIo ); 456 | if (JsNoError != errorCode) 457 | { 458 | break; 459 | } 460 | 461 | errorCode = this->bindRoutine("readMsr", BindingDbgEng::ReadMsr); 462 | if (JsNoError != errorCode) 463 | { 464 | break; 465 | } 466 | 467 | errorCode = this->bindRoutine("readPhysical", BindingDbgEng::ReadPhysical); 468 | if (JsNoError != errorCode) 469 | { 470 | break; 471 | } 472 | 473 | errorCode = this->bindRoutine("readProcessor", BindingDbgEng::ReadProcessor); 474 | if (JsNoError != errorCode) 475 | { 476 | break; 477 | } 478 | 479 | errorCode = this->bindRoutine("readVirtual", BindingDbgEng::ReadVirtual); 480 | if (JsNoError != errorCode) 481 | { 482 | break; 483 | } 484 | 485 | errorCode = this->bindRoutine("searchVirtual", BindingDbgEng::SearchVirtual); 486 | if (JsNoError != errorCode) 487 | { 488 | break; 489 | } 490 | 491 | errorCode = this->bindRoutine("writeBus", BindingDbgEng::WriteBus); 492 | if (JsNoError != errorCode) 493 | { 494 | break; 495 | } 496 | 497 | errorCode = this->bindRoutine("writeControl", BindingDbgEng::WriteControl); 498 | if (JsNoError != errorCode) 499 | { 500 | break; 501 | } 502 | 503 | errorCode = this->bindRoutine("writeIo", BindingDbgEng::WriteIo); 504 | if (JsNoError != errorCode) 505 | { 506 | break; 507 | } 508 | 509 | errorCode = this->bindRoutine("writeMsr", BindingDbgEng::WriteMsr); 510 | if (JsNoError != errorCode) 511 | { 512 | break; 513 | } 514 | 515 | errorCode = this->bindRoutine("writePhysical", BindingDbgEng::WritePhysical); 516 | if (JsNoError != errorCode) 517 | { 518 | break; 519 | } 520 | 521 | errorCode = this->bindRoutine("writeVirtual", BindingDbgEng::WriteVirtual); 522 | if (JsNoError != errorCode) 523 | { 524 | break; 525 | } 526 | 527 | 528 | finalCode = JsNoError; 529 | } while (false); 530 | 531 | return finalCode; 532 | } 533 | 534 | JsErrorCode BindingDbgEng::bindDebugRegisters() 535 | { 536 | JsErrorCode errorCode = JsErrorFatal; 537 | 538 | JsErrorCode finalCode = JsErrorFatal; 539 | 540 | do 541 | { 542 | 543 | errorCode = this->bindRoutine("getRegisterDescription" , BindingDbgEng::GetRegisterDescription ); 544 | if (JsNoError != errorCode) 545 | { 546 | break; 547 | } 548 | 549 | errorCode = this->bindRoutine("getFrameOffset", BindingDbgEng::GetFrameOffset); 550 | if (JsNoError != errorCode) 551 | { 552 | break; 553 | } 554 | 555 | errorCode = this->bindRoutine("getRegisterIndex", BindingDbgEng::GetRegisterIndex); 556 | if (JsNoError != errorCode) 557 | { 558 | break; 559 | } 560 | 561 | errorCode = this->bindRoutine("getInstructionOffset", BindingDbgEng::GetInstructionOffset); 562 | if (JsNoError != errorCode) 563 | { 564 | break; 565 | } 566 | 567 | errorCode = this->bindRoutine("getNumberRegisters", BindingDbgEng::GetNumberRegisters); 568 | if (JsNoError != errorCode) 569 | { 570 | break; 571 | } 572 | 573 | errorCode = this->bindRoutine("getStackOffset", BindingDbgEng::GetStackOffset); 574 | if (JsNoError != errorCode) 575 | { 576 | break; 577 | } 578 | 579 | errorCode = this->bindRoutine("getRegisterValue", BindingDbgEng::GetRegisterValue); 580 | if (JsNoError != errorCode) 581 | { 582 | break; 583 | } 584 | 585 | errorCode = this->bindRoutine("setRegisterValue", BindingDbgEng::SetRegisterValue); 586 | if (JsNoError != errorCode) 587 | { 588 | break; 589 | } 590 | 591 | finalCode = JsNoError; 592 | } while (false); 593 | 594 | return finalCode; 595 | } 596 | 597 | JsErrorCode BindingDbgEng::bindDebugSymbols() 598 | { 599 | JsErrorCode errorCode = JsErrorFatal; 600 | 601 | JsErrorCode finalCode = JsErrorFatal; 602 | 603 | do 604 | { 605 | 606 | errorCode = this->bindRoutine("getFieldOffset" , BindingDbgEng::GetFieldOffset ); 607 | if (JsNoError != errorCode) 608 | { 609 | break; 610 | } 611 | 612 | 613 | errorCode = this->bindRoutine("getModuleByIndex" , BindingDbgEng::GetModuleByIndex ); 614 | if (JsNoError != errorCode) 615 | { 616 | break; 617 | } 618 | 619 | errorCode = this->bindRoutine("getModuleByName", BindingDbgEng::GetModuleByName); 620 | if (JsNoError != errorCode) 621 | { 622 | break; 623 | } 624 | 625 | errorCode = this->bindRoutine("getModuleByOffset", BindingDbgEng::GetModuleByOffset); 626 | if (JsNoError != errorCode) 627 | { 628 | break; 629 | } 630 | 631 | errorCode = this->bindRoutine("getModuleNames", BindingDbgEng::GetModuleNames); 632 | if (JsNoError != errorCode) 633 | { 634 | break; 635 | } 636 | 637 | errorCode = this->bindRoutine("getModuleParameters", BindingDbgEng::GetModuleParameters); 638 | if (JsNoError != errorCode) 639 | { 640 | break; 641 | } 642 | 643 | errorCode = this->bindRoutine("getNameByOffset", BindingDbgEng::GetNameByOffset); 644 | if (JsNoError != errorCode) 645 | { 646 | break; 647 | } 648 | 649 | errorCode = this->bindRoutine("getNearNameByOffset", BindingDbgEng::GetNearNameByOffset); 650 | if (JsNoError != errorCode) 651 | { 652 | break; 653 | } 654 | 655 | errorCode = this->bindRoutine("getNumberModules", BindingDbgEng::GetNumberModules); 656 | if (JsNoError != errorCode) 657 | { 658 | break; 659 | } 660 | 661 | errorCode = this->bindRoutine("getOffsetByName", BindingDbgEng::GetOffsetByName); 662 | if (JsNoError != errorCode) 663 | { 664 | break; 665 | } 666 | 667 | errorCode = this->bindRoutine("getOffsetTypeId", BindingDbgEng::GetOffsetTypeId); 668 | if (JsNoError != errorCode) 669 | { 670 | break; 671 | } 672 | 673 | 674 | errorCode = this->bindRoutine("getSymbolModule", BindingDbgEng::GetSymbolModule); 675 | if (JsNoError != errorCode) 676 | { 677 | break; 678 | } 679 | 680 | errorCode = this->bindRoutine("getSymbolPath", BindingDbgEng::GetSymbolPath); 681 | if (JsNoError != errorCode) 682 | { 683 | break; 684 | } 685 | 686 | errorCode = this->bindRoutine("getSymbolTypeId", BindingDbgEng::GetSymbolTypeId); 687 | if (JsNoError != errorCode) 688 | { 689 | break; 690 | } 691 | 692 | errorCode = this->bindRoutine("getTypeId", BindingDbgEng::GetTypeId); 693 | if (JsNoError != errorCode) 694 | { 695 | break; 696 | } 697 | 698 | errorCode = this->bindRoutine("getTypeName", BindingDbgEng::GetTypeName); 699 | if (JsNoError != errorCode) 700 | { 701 | break; 702 | } 703 | 704 | errorCode = this->bindRoutine("getTypeSize", BindingDbgEng::GetTypeSize); 705 | if (JsNoError != errorCode) 706 | { 707 | break; 708 | } 709 | 710 | 711 | errorCode = this->bindRoutine("reload", BindingDbgEng::Reload); 712 | if (JsNoError != errorCode) 713 | { 714 | break; 715 | } 716 | 717 | errorCode = this->bindRoutine("setSymbolPath", BindingDbgEng::SetSymbolPath); 718 | if (JsNoError != errorCode) 719 | { 720 | break; 721 | } 722 | 723 | finalCode = JsNoError; 724 | } while (false); 725 | 726 | return finalCode; 727 | } 728 | 729 | JsErrorCode BindingDbgEng::bindDebugSystemObjects() 730 | { 731 | JsErrorCode errorCode = JsErrorFatal; 732 | 733 | JsErrorCode finalCode = JsErrorFatal; 734 | 735 | do 736 | { 737 | 738 | errorCode = this->bindRoutine("getCurrentProcessDataOffset" , BindingDbgEng::GetCurrentProcessDataOffset ); 739 | if (JsNoError != errorCode) 740 | { 741 | break; 742 | } 743 | 744 | errorCode = this->bindRoutine("getCurrentProcessId" , BindingDbgEng::GetCurrentProcessId ); 745 | if (JsNoError != errorCode) 746 | { 747 | break; 748 | } 749 | 750 | errorCode = this->bindRoutine("getCurrentProcessPeb", BindingDbgEng::GetCurrentProcessPeb); 751 | if (JsNoError != errorCode) 752 | { 753 | break; 754 | } 755 | 756 | errorCode = this->bindRoutine("getCurrentProcessSystemId", BindingDbgEng::GetCurrentProcessSystemId); 757 | if (JsNoError != errorCode) 758 | { 759 | break; 760 | } 761 | 762 | errorCode = this->bindRoutine("getCurrentThreadDataOffset", BindingDbgEng::GetCurrentThreadDataOffset); 763 | if (JsNoError != errorCode) 764 | { 765 | break; 766 | } 767 | 768 | errorCode = this->bindRoutine("getCurrentThreadId", BindingDbgEng::GetCurrentThreadId); 769 | if (JsNoError != errorCode) 770 | { 771 | break; 772 | } 773 | 774 | errorCode = this->bindRoutine("getCurrentThreadSystemId", BindingDbgEng::GetCurrentThreadSystemId); 775 | if (JsNoError != errorCode) 776 | { 777 | break; 778 | } 779 | 780 | errorCode = this->bindRoutine("getCurrentThreadTeb", BindingDbgEng::GetCurrentThreadTeb); 781 | if (JsNoError != errorCode) 782 | { 783 | break; 784 | } 785 | 786 | errorCode = this->bindRoutine("getThreadIdByProcessor", BindingDbgEng::GetThreadIdByProcessor); 787 | if (JsNoError != errorCode) 788 | { 789 | break; 790 | } 791 | 792 | errorCode = this->bindRoutine("setCurrentThreadId", BindingDbgEng::SetCurrentThreadId); 793 | if (JsNoError != errorCode) 794 | { 795 | break; 796 | } 797 | 798 | 799 | finalCode = JsNoError; 800 | } while (false); 801 | 802 | return finalCode; 803 | } 804 | 805 | 806 | JsErrorCode BindingDbgEng::bindDebugSystemObjects2() 807 | { 808 | JsErrorCode errorCode = JsErrorFatal; 809 | 810 | JsErrorCode finalCode = JsErrorFatal; 811 | 812 | do 813 | { 814 | 815 | errorCode = this->bindRoutine("getImplicitProcessDataOffset" , BindingDbgEng::GetImplicitProcessDataOffset ); 816 | if (JsNoError != errorCode) 817 | { 818 | break; 819 | } 820 | 821 | errorCode = this->bindRoutine("getImplicitThreadDataOffset" , BindingDbgEng::GetImplicitThreadDataOffset ); 822 | if (JsNoError != errorCode) 823 | { 824 | break; 825 | } 826 | 827 | errorCode = this->bindRoutine("setImplicitProcessDataOffset" , BindingDbgEng::SetImplicitProcessDataOffset ); 828 | if (JsNoError != errorCode) 829 | { 830 | break; 831 | } 832 | 833 | errorCode = this->bindRoutine("setImplicitThreadDataOffset" , BindingDbgEng::SetImplicitThreadDataOffset ); 834 | if (JsNoError != errorCode) 835 | { 836 | break; 837 | } 838 | 839 | 840 | finalCode = JsNoError; 841 | } while (false); 842 | 843 | return finalCode; 844 | } 845 | -------------------------------------------------------------------------------- /src/binding/dbgeng/binding_registers.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file binding_registers.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | #include 9 | 10 | #include "binding_dbgeng.h" 11 | 12 | 13 | 14 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetRegisterDescription( 15 | 16 | _In_ JsValueRef callee, 17 | 18 | _In_ bool isConstructCall, 19 | 20 | _In_ JsValueRef *arguments, 21 | 22 | _In_ unsigned short argumentCount, 23 | 24 | _In_opt_ void *callbackState 25 | ) 26 | { 27 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 28 | 29 | JsValueRef result = nullptr; 30 | 31 | JsErrorCode errorCode = JsErrorFatal; 32 | 33 | HRESULT hr = E_FAIL; 34 | 35 | uint32_t arg1Index = 0; 36 | 37 | std::vector name; 38 | 39 | ULONG nameBufferSize = 0; 40 | 41 | ULONG nameDataSize = 0; 42 | 43 | DEBUG_REGISTER_DESCRIPTION description = {0}; 44 | 45 | JsValueRef info = nullptr; 46 | 47 | do 48 | { 49 | if (argumentCount < 2) 50 | { 51 | JsExThrowError("invalid argument count %d" , argumentCount); 52 | break; 53 | } 54 | 55 | errorCode = JsExAssumeUint32( arguments[1] , &arg1Index ); 56 | if ( JsNoError != errorCode ) 57 | { 58 | JsExThrowError("assume index fail 0x%08X" , errorCode); 59 | break; 60 | } 61 | 62 | pthis->m_debugRegisters->GetDescription( 63 | arg1Index , 64 | nullptr, 65 | 0, 66 | &nameBufferSize, 67 | &description 68 | ); 69 | 70 | if ( 0 != nameBufferSize ) 71 | { 72 | name.resize( nameBufferSize ); 73 | } 74 | 75 | hr = pthis->m_debugRegisters->GetDescription( 76 | arg1Index , 77 | 0 == nameBufferSize ? nullptr : name.data(), 78 | nameBufferSize, 79 | &nameDataSize, 80 | &description 81 | ); 82 | 83 | if ( !SUCCEEDED(hr) ) 84 | { 85 | JsExThrowError("GetDescription fail 0x%08X" , hr); 86 | break ; 87 | } 88 | 89 | errorCode = JsCreateObject( &info ); 90 | if ( JsNoError != errorCode ) 91 | { 92 | JsExThrowError("assume index fail 0x%08X" , errorCode); 93 | break; 94 | } 95 | 96 | if ( nameDataSize > 1 ) 97 | { 98 | errorCode = JsExSetPropertyString( 99 | info , 100 | "name" , 101 | std::string( name.data() , nameDataSize - 1 ), 102 | true 103 | ); 104 | if ( JsNoError != errorCode ) 105 | { 106 | JsExThrowError("JsExSetPropertyInt fail 0x%08X" , errorCode); 107 | break; 108 | } 109 | } 110 | else 111 | { 112 | errorCode = JsExSetPropertyString( 113 | info , 114 | "name" , 115 | "", 116 | true 117 | ); 118 | if ( JsNoError != errorCode ) 119 | { 120 | JsExThrowError("JsExSetPropertyInt fail 0x%08X" , errorCode); 121 | break; 122 | } 123 | 124 | } 125 | 126 | errorCode = JsExSetPropertyInt( info , "type" , (int)description.Type , true ); 127 | if ( JsNoError != errorCode ) 128 | { 129 | JsExThrowError("JsExSetPropertyInt fail 0x%08X" , errorCode); 130 | break; 131 | } 132 | 133 | errorCode = JsExSetPropertyInt( info , "flags" , (int)description.Flags , true ); 134 | if ( JsNoError != errorCode ) 135 | { 136 | JsExThrowError("JsExSetPropertyInt fail 0x%08X" , errorCode); 137 | break; 138 | } 139 | 140 | if ( description.Flags & DEBUG_REGISTER_SUB_REGISTER ) 141 | { 142 | errorCode = JsExSetPropertyInt( info , "subregMaster" , (int)description.SubregMaster , true ); 143 | if ( JsNoError != errorCode ) 144 | { 145 | JsExThrowError("JsExSetPropertyInt fail 0x%08X" , errorCode); 146 | break; 147 | } 148 | 149 | errorCode = JsExSetPropertyInt( info , "subregLength" , (int)description.SubregLength , true ); 150 | if ( JsNoError != errorCode ) 151 | { 152 | JsExThrowError("JsExSetPropertyInt fail 0x%08X" , errorCode); 153 | break; 154 | } 155 | 156 | errorCode = JsExSetPropertyUint64( info , "subregMask" , description.SubregMask , true ); 157 | if ( JsNoError != errorCode ) 158 | { 159 | JsExThrowError("JsExSetPropertyInt fail 0x%08X" , errorCode); 160 | break; 161 | } 162 | 163 | errorCode = JsExSetPropertyInt( info , "subregShift" , (int)description.SubregShift , true ); 164 | if ( JsNoError != errorCode ) 165 | { 166 | JsExThrowError("JsExSetPropertyInt fail 0x%08X" , errorCode); 167 | break; 168 | } 169 | } 170 | 171 | 172 | result = info; 173 | 174 | } while (false); 175 | 176 | return result; 177 | } 178 | 179 | 180 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetFrameOffset( 181 | 182 | _In_ JsValueRef callee, 183 | 184 | _In_ bool isConstructCall, 185 | 186 | _In_ JsValueRef *arguments, 187 | 188 | _In_ unsigned short argumentCount, 189 | 190 | _In_opt_ void *callbackState 191 | ) 192 | { 193 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 194 | 195 | JsValueRef result = nullptr; 196 | 197 | JsErrorCode errorCode = JsErrorFatal; 198 | 199 | HRESULT hr = E_FAIL; 200 | 201 | ULONG64 offset = 0; 202 | 203 | do 204 | { 205 | 206 | hr = pthis->m_debugRegisters->GetFrameOffset( &offset ); 207 | if ( !SUCCEEDED(hr) ) 208 | { 209 | JsExThrowError("GetIndexByName fail 0x%08X" , hr); 210 | break ; 211 | } 212 | 213 | JsExCreateUint64( offset , &result ); 214 | 215 | } while (false); 216 | 217 | return result; 218 | } 219 | 220 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetRegisterIndex( 221 | 222 | _In_ JsValueRef callee, 223 | 224 | _In_ bool isConstructCall, 225 | 226 | _In_ JsValueRef *arguments, 227 | 228 | _In_ unsigned short argumentCount, 229 | 230 | _In_opt_ void *callbackState 231 | ) 232 | { 233 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 234 | 235 | JsValueRef result = nullptr; 236 | 237 | JsErrorCode errorCode = JsErrorFatal; 238 | 239 | HRESULT hr = E_FAIL; 240 | 241 | std::string arg1Name; 242 | 243 | ULONG index = 0; 244 | 245 | do 246 | { 247 | if (argumentCount < 1) 248 | { 249 | JsExThrowError("invalid argument count %d" , argumentCount); 250 | break; 251 | } 252 | 253 | errorCode = JsExAssumeString( arguments[1] , true , &arg1Name ); 254 | if ( JsNoError != errorCode ) 255 | { 256 | JsExThrowError("assume name fail 0x%08X" , errorCode); 257 | break; 258 | } 259 | 260 | hr = pthis->m_debugRegisters->GetIndexByName( arg1Name.c_str() , &index ); 261 | if ( !SUCCEEDED(hr) ) 262 | { 263 | JsExThrowError("GetIndexByName fail 0x%08X" , hr); 264 | break ; 265 | } 266 | 267 | JsIntToNumber( (int)index , &result ); 268 | 269 | } while (false); 270 | 271 | return result; 272 | } 273 | 274 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetInstructionOffset( 275 | 276 | _In_ JsValueRef callee, 277 | 278 | _In_ bool isConstructCall, 279 | 280 | _In_ JsValueRef *arguments, 281 | 282 | _In_ unsigned short argumentCount, 283 | 284 | _In_opt_ void *callbackState 285 | ) 286 | { 287 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 288 | 289 | JsValueRef result = nullptr; 290 | 291 | JsErrorCode errorCode = JsErrorFatal; 292 | 293 | HRESULT hr = E_FAIL; 294 | 295 | ULONG64 offset = 0; 296 | 297 | do 298 | { 299 | hr = pthis->m_debugRegisters->GetInstructionOffset( &offset ); 300 | if ( !SUCCEEDED(hr) ) 301 | { 302 | JsExThrowError("GetInstructionOffset fail 0x%08X" , hr); 303 | break ; 304 | } 305 | 306 | JsExCreateUint64( offset , &result ); 307 | 308 | } while (false); 309 | 310 | return result; 311 | } 312 | 313 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetNumberRegisters( 314 | 315 | _In_ JsValueRef callee, 316 | 317 | _In_ bool isConstructCall, 318 | 319 | _In_ JsValueRef *arguments, 320 | 321 | _In_ unsigned short argumentCount, 322 | 323 | _In_opt_ void *callbackState 324 | ) 325 | { 326 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 327 | 328 | JsValueRef result = nullptr; 329 | 330 | JsErrorCode errorCode = JsErrorFatal; 331 | 332 | HRESULT hr = E_FAIL; 333 | 334 | ULONG value = 0; 335 | 336 | do 337 | { 338 | hr = pthis->m_debugRegisters->GetNumberRegisters( &value ); 339 | if ( !SUCCEEDED(hr) ) 340 | { 341 | JsExThrowError("GetNumberRegisters fail 0x%08X" , hr); 342 | break ; 343 | } 344 | 345 | JsIntToNumber( (int)value , &result ); 346 | 347 | } while (false); 348 | 349 | return result; 350 | } 351 | 352 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetStackOffset( 353 | 354 | _In_ JsValueRef callee, 355 | 356 | _In_ bool isConstructCall, 357 | 358 | _In_ JsValueRef *arguments, 359 | 360 | _In_ unsigned short argumentCount, 361 | 362 | _In_opt_ void *callbackState 363 | ) 364 | { 365 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 366 | 367 | JsValueRef result = nullptr; 368 | 369 | JsErrorCode errorCode = JsErrorFatal; 370 | 371 | HRESULT hr = E_FAIL; 372 | 373 | ULONG64 offset = 0; 374 | 375 | do 376 | { 377 | hr = pthis->m_debugRegisters->GetStackOffset( &offset ); 378 | if ( !SUCCEEDED(hr) ) 379 | { 380 | JsExThrowError("GetStackOffset fail 0x%08X" , hr); 381 | break ; 382 | } 383 | 384 | JsExCreateUint64( offset , &result ); 385 | 386 | } while (false); 387 | 388 | return result; 389 | } 390 | 391 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetRegisterValue( 392 | 393 | _In_ JsValueRef callee, 394 | 395 | _In_ bool isConstructCall, 396 | 397 | _In_ JsValueRef *arguments, 398 | 399 | _In_ unsigned short argumentCount, 400 | 401 | _In_opt_ void *callbackState 402 | ) 403 | { 404 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 405 | 406 | JsValueRef result = nullptr; 407 | 408 | JsErrorCode errorCode = JsErrorFatal; 409 | 410 | HRESULT hr = E_FAIL; 411 | 412 | uint32_t arg1Index = 0; 413 | 414 | DEBUG_VALUE value = {0}; 415 | 416 | JsValueRef data = nullptr; 417 | 418 | JsValueRef info = nullptr; 419 | 420 | 421 | do 422 | { 423 | if (argumentCount < 2) 424 | { 425 | JsExThrowError("invalid argument count %d" , argumentCount); 426 | break; 427 | } 428 | 429 | errorCode = JsExAssumeUint32( arguments[1] , &arg1Index ); 430 | if ( JsNoError != errorCode ) 431 | { 432 | JsExThrowError("assume index fail 0x%08X" , errorCode); 433 | break; 434 | } 435 | 436 | hr = pthis->m_debugRegisters->GetValue( arg1Index , &value ); 437 | if ( !SUCCEEDED(hr) ) 438 | { 439 | JsExThrowError("GetValue fail 0x%08X" , hr); 440 | break ; 441 | } 442 | 443 | if ( DEBUG_VALUE_INT8 == value.Type ) 444 | { 445 | JsIntToNumber( (int)value.I8 , &data ); 446 | } 447 | else if ( DEBUG_VALUE_INT16 == value.Type ) 448 | { 449 | JsIntToNumber( (int)value.I16 , &data ); 450 | } 451 | else if ( DEBUG_VALUE_INT32 == value.Type ) 452 | { 453 | JsIntToNumber( (int)value.I32 , &data ); 454 | } 455 | else if ( DEBUG_VALUE_INT64 == value.Type ) 456 | { 457 | JsExCreateUint64( value.I64 , &data ); 458 | } 459 | else if ( DEBUG_VALUE_FLOAT32 == value.Type ) 460 | { 461 | JsDoubleToNumber( (double)value.F32 , &data ); 462 | } 463 | else if ( DEBUG_VALUE_FLOAT64 == value.Type ) 464 | { 465 | JsExCreateUint8Array( value.RawBytes , 8 , &data); 466 | } 467 | else if ( DEBUG_VALUE_FLOAT80 == value.Type ) 468 | { 469 | JsExCreateUint8Array( value.F80Bytes , 10 , &data); 470 | } 471 | else if ( DEBUG_VALUE_FLOAT128 == value.Type ) 472 | { 473 | JsExCreateUint8Array( value.F128Bytes , 16 , &data); 474 | } 475 | else if ( DEBUG_VALUE_VECTOR64 == value.Type ) 476 | { 477 | JsExCreateUint8Array( value.VI8 , 8, &data); 478 | } 479 | else if ( DEBUG_VALUE_VECTOR128 == value.Type ) 480 | { 481 | JsExCreateUint8Array( value.VI8 , 16, &data); 482 | } 483 | else 484 | { 485 | JsExCreateUint8Array( value.RawBytes , ARRAYSIZE(value.RawBytes) , &data); 486 | } 487 | 488 | errorCode = JsCreateObject( &info ); 489 | if ( JsNoError != errorCode ) 490 | { 491 | JsExThrowError("JsCreateObject fail 0x%08X" , errorCode); 492 | break; 493 | } 494 | 495 | JsExSetProperty(info , "value" , data , true ); 496 | 497 | JsExSetPropertyUint32(info , "type" , value.Type , true ); 498 | 499 | result = info; 500 | 501 | } while (false); 502 | 503 | return result; 504 | } 505 | 506 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::SetRegisterValue( 507 | 508 | _In_ JsValueRef callee, 509 | 510 | _In_ bool isConstructCall, 511 | 512 | _In_ JsValueRef *arguments, 513 | 514 | _In_ unsigned short argumentCount, 515 | 516 | _In_opt_ void *callbackState 517 | ) 518 | { 519 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 520 | 521 | JsValueRef result = nullptr; 522 | 523 | JsErrorCode errorCode = JsErrorFatal; 524 | 525 | HRESULT hr = E_FAIL; 526 | 527 | uint32_t arg1Index = 0; 528 | 529 | DEBUG_VALUE value = {0}; 530 | 531 | JsValueType valueType = JsUndefined; 532 | 533 | uint32_t bytes = 0; 534 | 535 | do 536 | { 537 | if (argumentCount < 4) 538 | { 539 | JsExThrowError("invalid argument count %d" , argumentCount); 540 | break; 541 | } 542 | 543 | errorCode = JsExAssumeUint32( arguments[1] , &arg1Index ); 544 | if ( JsNoError != errorCode ) 545 | { 546 | JsExThrowError("assume index fail 0x%08X" , errorCode); 547 | break; 548 | } 549 | 550 | errorCode = JsExAssumeUint32( arguments[2] , (uint32_t*)&(value.Type) ); 551 | if ( JsNoError != errorCode ) 552 | { 553 | JsExThrowError("assume type fail 0x%08X" , errorCode); 554 | break; 555 | } 556 | 557 | if ( DEBUG_VALUE_INT8 == value.Type ) 558 | { 559 | bytes = 1; 560 | } 561 | else if ( DEBUG_VALUE_INT16 == value.Type ) 562 | { 563 | bytes = 2; 564 | } 565 | else if ( DEBUG_VALUE_INT32 == value.Type ) 566 | { 567 | bytes = 4; 568 | } 569 | else if ( DEBUG_VALUE_INT64 == value.Type ) 570 | { 571 | bytes = 8; 572 | } 573 | else if ( DEBUG_VALUE_FLOAT32 == value.Type ) 574 | { 575 | bytes = 4; 576 | } 577 | else if ( DEBUG_VALUE_FLOAT64 == value.Type ) 578 | { 579 | bytes = 8; 580 | } 581 | else if ( DEBUG_VALUE_FLOAT80 == value.Type ) 582 | { 583 | bytes = 10; 584 | } 585 | else if ( DEBUG_VALUE_FLOAT128 == value.Type ) 586 | { 587 | bytes = 16; 588 | } 589 | else if ( DEBUG_VALUE_VECTOR64 == value.Type ) 590 | { 591 | bytes = 8; 592 | } 593 | else if ( DEBUG_VALUE_VECTOR128 == value.Type ) 594 | { 595 | bytes = 16; 596 | } 597 | else 598 | { 599 | JsExThrowError("not supported type fail %d" , value.Type); 600 | break; 601 | } 602 | 603 | errorCode = JsGetValueType( arguments[3] , &valueType); 604 | if ( JsNoError != errorCode ) 605 | { 606 | JsExThrowError("JsGetValueType fail 0x%08X" , errorCode); 607 | break; 608 | } 609 | 610 | if ( JsArray == valueType ) 611 | { 612 | errorCode = JsExAssumeUint8Array( 613 | arguments[3] , 614 | (uint8_t *)&(value.RawBytes), 615 | bytes 616 | ); 617 | if ( JsNoError != errorCode ) 618 | { 619 | JsExThrowError("JsExAssumeUint8Array fail 0x%08X" , errorCode); 620 | break; 621 | } 622 | } 623 | else if ( JsNumber == valueType ) 624 | { 625 | errorCode = JsExAssumeUint32( arguments[3] , (uint32_t *)&(value.I32) ); 626 | if ( JsNoError != errorCode ) 627 | { 628 | JsExThrowError("JsExAssumeUint32 fail 0x%08X" , errorCode); 629 | break; 630 | } 631 | } 632 | else if ( JsString == valueType ) 633 | { 634 | errorCode = JsExAssumeUint64( arguments[3] , (uint64_t *)&(value.I64) ); 635 | if ( JsNoError != errorCode ) 636 | { 637 | JsExThrowError("JsExAssumeUint64 fail 0x%08X" , errorCode); 638 | break; 639 | } 640 | } 641 | else 642 | { 643 | JsExThrowError("not supported value type 0x%08X" , valueType); 644 | break; 645 | } 646 | 647 | hr = pthis->m_debugRegisters->SetValue( arg1Index , &value ); 648 | if ( !SUCCEEDED(hr) ) 649 | { 650 | JsExThrowError("SetValue fail 0x%08X" , hr); 651 | break ; 652 | } 653 | 654 | } while (false); 655 | 656 | return result; 657 | } -------------------------------------------------------------------------------- /src/binding/dbgeng/binding_system_objects.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file binding_system_object.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | #include 9 | 10 | #include "binding_dbgeng.h" 11 | 12 | 13 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetCurrentProcessDataOffset( 14 | 15 | _In_ JsValueRef callee, 16 | 17 | _In_ bool isConstructCall, 18 | 19 | _In_ JsValueRef *arguments, 20 | 21 | _In_ unsigned short argumentCount, 22 | 23 | _In_opt_ void *callbackState 24 | ) 25 | { 26 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 27 | 28 | JsValueRef result = nullptr; 29 | 30 | JsErrorCode errorCode = JsErrorFatal; 31 | 32 | HRESULT hr = E_FAIL; 33 | 34 | ULONG64 offset = 0; 35 | 36 | do 37 | { 38 | hr = pthis->m_debugSystemObjects->GetCurrentProcessDataOffset(&offset); 39 | if ( !SUCCEEDED(hr) ) 40 | { 41 | JsExThrowError("GetCurrentProcessDataOffset fail 0x%08X" , hr); 42 | break ; 43 | } 44 | 45 | JsExCreateUint64( offset , &result); 46 | 47 | } while (false); 48 | 49 | return result; 50 | } 51 | 52 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetCurrentProcessId( 53 | 54 | _In_ JsValueRef callee, 55 | 56 | _In_ bool isConstructCall, 57 | 58 | _In_ JsValueRef *arguments, 59 | 60 | _In_ unsigned short argumentCount, 61 | 62 | _In_opt_ void *callbackState 63 | ) 64 | { 65 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 66 | 67 | JsValueRef result = nullptr; 68 | 69 | JsErrorCode errorCode = JsErrorFatal; 70 | 71 | HRESULT hr = E_FAIL; 72 | 73 | ULONG id = 0; 74 | 75 | do 76 | { 77 | hr = pthis->m_debugSystemObjects->GetCurrentProcessId(&id); 78 | if ( !SUCCEEDED(hr) ) 79 | { 80 | JsExThrowError("GetCurrentProcessId fail 0x%08X" , hr); 81 | break ; 82 | } 83 | 84 | JsIntToNumber( (int)id , &result); 85 | 86 | } while (false); 87 | 88 | return result; 89 | } 90 | 91 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetCurrentProcessPeb( 92 | 93 | _In_ JsValueRef callee, 94 | 95 | _In_ bool isConstructCall, 96 | 97 | _In_ JsValueRef *arguments, 98 | 99 | _In_ unsigned short argumentCount, 100 | 101 | _In_opt_ void *callbackState 102 | ) 103 | { 104 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 105 | 106 | JsValueRef result = nullptr; 107 | 108 | JsErrorCode errorCode = JsErrorFatal; 109 | 110 | HRESULT hr = E_FAIL; 111 | 112 | ULONG64 offset = 0; 113 | 114 | do 115 | { 116 | hr = pthis->m_debugSystemObjects->GetCurrentProcessPeb(&offset); 117 | if ( !SUCCEEDED(hr) ) 118 | { 119 | JsExThrowError("GetCurrentProcessPeb fail 0x%08X" , hr); 120 | break ; 121 | } 122 | 123 | JsExCreateUint64( offset , &result); 124 | 125 | } while (false); 126 | 127 | return result; 128 | } 129 | 130 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetCurrentProcessSystemId( 131 | 132 | _In_ JsValueRef callee, 133 | 134 | _In_ bool isConstructCall, 135 | 136 | _In_ JsValueRef *arguments, 137 | 138 | _In_ unsigned short argumentCount, 139 | 140 | _In_opt_ void *callbackState 141 | ) 142 | { 143 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 144 | 145 | JsValueRef result = nullptr; 146 | 147 | JsErrorCode errorCode = JsErrorFatal; 148 | 149 | HRESULT hr = E_FAIL; 150 | 151 | ULONG id = 0; 152 | 153 | do 154 | { 155 | hr = pthis->m_debugSystemObjects->GetCurrentProcessSystemId(&id); 156 | if ( !SUCCEEDED(hr) ) 157 | { 158 | JsExThrowError("GetCurrentProcessSystemId fail 0x%08X" , hr); 159 | break ; 160 | } 161 | 162 | JsIntToNumber( (int)id , &result); 163 | 164 | } while (false); 165 | 166 | return result; 167 | } 168 | 169 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetCurrentThreadDataOffset( 170 | 171 | _In_ JsValueRef callee, 172 | 173 | _In_ bool isConstructCall, 174 | 175 | _In_ JsValueRef *arguments, 176 | 177 | _In_ unsigned short argumentCount, 178 | 179 | _In_opt_ void *callbackState 180 | ) 181 | { 182 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 183 | 184 | JsValueRef result = nullptr; 185 | 186 | JsErrorCode errorCode = JsErrorFatal; 187 | 188 | HRESULT hr = E_FAIL; 189 | 190 | ULONG64 offset = 0; 191 | 192 | do 193 | { 194 | hr = pthis->m_debugSystemObjects->GetCurrentThreadDataOffset(&offset); 195 | if ( !SUCCEEDED(hr) ) 196 | { 197 | JsExThrowError("GetCurrentThreadDataOffset fail 0x%08X" , hr); 198 | break ; 199 | } 200 | 201 | JsExCreateUint64( offset , &result); 202 | 203 | } while (false); 204 | 205 | return result; 206 | } 207 | 208 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetCurrentThreadId( 209 | 210 | _In_ JsValueRef callee, 211 | 212 | _In_ bool isConstructCall, 213 | 214 | _In_ JsValueRef *arguments, 215 | 216 | _In_ unsigned short argumentCount, 217 | 218 | _In_opt_ void *callbackState 219 | ) 220 | { 221 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 222 | 223 | JsValueRef result = nullptr; 224 | 225 | JsErrorCode errorCode = JsErrorFatal; 226 | 227 | HRESULT hr = E_FAIL; 228 | 229 | ULONG id = 0; 230 | 231 | do 232 | { 233 | hr = pthis->m_debugSystemObjects->GetCurrentThreadId(&id); 234 | if ( !SUCCEEDED(hr) ) 235 | { 236 | JsExThrowError("GetCurrentThreadId fail 0x%08X" , hr); 237 | break ; 238 | } 239 | 240 | JsIntToNumber( (int)id , &result); 241 | 242 | } while (false); 243 | 244 | return result; 245 | } 246 | 247 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetCurrentThreadSystemId( 248 | 249 | _In_ JsValueRef callee, 250 | 251 | _In_ bool isConstructCall, 252 | 253 | _In_ JsValueRef *arguments, 254 | 255 | _In_ unsigned short argumentCount, 256 | 257 | _In_opt_ void *callbackState 258 | ) 259 | { 260 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 261 | 262 | JsValueRef result = nullptr; 263 | 264 | JsErrorCode errorCode = JsErrorFatal; 265 | 266 | HRESULT hr = E_FAIL; 267 | 268 | ULONG id = 0; 269 | 270 | do 271 | { 272 | hr = pthis->m_debugSystemObjects->GetCurrentThreadSystemId(&id); 273 | if ( !SUCCEEDED(hr) ) 274 | { 275 | JsExThrowError("GetCurrentThreadSystemId fail 0x%08X" , hr); 276 | break ; 277 | } 278 | 279 | JsIntToNumber( (int)id , &result); 280 | 281 | } while (false); 282 | 283 | return result; 284 | } 285 | 286 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetCurrentThreadTeb( 287 | 288 | _In_ JsValueRef callee, 289 | 290 | _In_ bool isConstructCall, 291 | 292 | _In_ JsValueRef *arguments, 293 | 294 | _In_ unsigned short argumentCount, 295 | 296 | _In_opt_ void *callbackState 297 | ) 298 | { 299 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 300 | 301 | JsValueRef result = nullptr; 302 | 303 | JsErrorCode errorCode = JsErrorFatal; 304 | 305 | HRESULT hr = E_FAIL; 306 | 307 | ULONG64 offset = 0; 308 | 309 | do 310 | { 311 | hr = pthis->m_debugSystemObjects->GetCurrentThreadTeb(&offset); 312 | if ( !SUCCEEDED(hr) ) 313 | { 314 | JsExThrowError("GetCurrentThreadTeb fail 0x%08X" , hr); 315 | break ; 316 | } 317 | 318 | JsExCreateUint64( offset , &result); 319 | 320 | } while (false); 321 | 322 | return result; 323 | } 324 | 325 | 326 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetThreadIdByProcessor( 327 | 328 | _In_ JsValueRef callee, 329 | 330 | _In_ bool isConstructCall, 331 | 332 | _In_ JsValueRef *arguments, 333 | 334 | _In_ unsigned short argumentCount, 335 | 336 | _In_opt_ void *callbackState 337 | ) 338 | { 339 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 340 | 341 | JsValueRef result = nullptr; 342 | 343 | JsErrorCode errorCode = JsErrorFatal; 344 | 345 | HRESULT hr = E_FAIL; 346 | 347 | uint32_t arg1Processor = 0; 348 | 349 | ULONG id = 0; 350 | 351 | do 352 | { 353 | if ( argumentCount < 2 ) 354 | { 355 | JsExThrowError("invalid argument cound %d" , argumentCount); 356 | break; 357 | } 358 | 359 | errorCode = JsExAssumeUint32( arguments[1] , &arg1Processor ); 360 | if ( JsNoError != errorCode ) 361 | { 362 | JsExThrowError("assume processor fail 0x%08X" , errorCode); 363 | break; 364 | } 365 | 366 | hr = pthis->m_debugSystemObjects->GetThreadIdByProcessor(arg1Processor , &id); 367 | if ( !SUCCEEDED(hr) ) 368 | { 369 | JsExThrowError("GetThreadIdByProcessor fail 0x%08X" , hr); 370 | break ; 371 | } 372 | 373 | JsIntToNumber( (int)id , &result); 374 | 375 | } while (false); 376 | 377 | return result; 378 | } 379 | 380 | 381 | 382 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::SetCurrentThreadId( 383 | 384 | _In_ JsValueRef callee, 385 | 386 | _In_ bool isConstructCall, 387 | 388 | _In_ JsValueRef *arguments, 389 | 390 | _In_ unsigned short argumentCount, 391 | 392 | _In_opt_ void *callbackState 393 | ) 394 | { 395 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 396 | 397 | JsValueRef result = nullptr; 398 | 399 | JsErrorCode errorCode = JsErrorFatal; 400 | 401 | HRESULT hr = E_FAIL; 402 | 403 | uint64_t arg1Id = 0; 404 | 405 | 406 | do 407 | { 408 | if ( argumentCount < 2 ) 409 | { 410 | JsExThrowError("invalid argument cound %d" , argumentCount); 411 | break; 412 | } 413 | 414 | errorCode = JsExAssumeUint64( arguments[1] , &arg1Id ); 415 | if ( JsNoError != errorCode ) 416 | { 417 | JsExThrowError("assume id fail 0x%08X" , errorCode); 418 | break; 419 | } 420 | 421 | hr = pthis->m_debugSystemObjects->SetCurrentThreadId(arg1Id); 422 | if ( SUCCEEDED(hr) ) 423 | { 424 | JsBoolToBoolean(true , &result); 425 | } 426 | else 427 | { 428 | JsBoolToBoolean(false , &result); 429 | } 430 | 431 | } while (false); 432 | 433 | return result; 434 | } 435 | 436 | -------------------------------------------------------------------------------- /src/binding/dbgeng/binding_system_objects2.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file binding_system_objects2.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | */ 7 | 8 | #include 9 | 10 | #include "binding_dbgeng.h" 11 | 12 | 13 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetImplicitProcessDataOffset( 14 | 15 | _In_ JsValueRef callee, 16 | 17 | _In_ bool isConstructCall, 18 | 19 | _In_ JsValueRef *arguments, 20 | 21 | _In_ unsigned short argumentCount, 22 | 23 | _In_opt_ void *callbackState 24 | ) 25 | { 26 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 27 | 28 | JsValueRef result = nullptr; 29 | 30 | JsErrorCode errorCode = JsErrorFatal; 31 | 32 | HRESULT hr = E_FAIL; 33 | 34 | ULONG64 offset = 0; 35 | 36 | do 37 | { 38 | hr = pthis->m_debugSystemObjects2->GetImplicitProcessDataOffset(&offset); 39 | if ( !SUCCEEDED(hr) ) 40 | { 41 | JsExThrowError("GetImplicitProcessDataOffset fail 0x%08X" , hr); 42 | break ; 43 | } 44 | 45 | JsExCreateUint64( offset , &result); 46 | 47 | } while (false); 48 | 49 | return result; 50 | } 51 | 52 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::GetImplicitThreadDataOffset( 53 | 54 | _In_ JsValueRef callee, 55 | 56 | _In_ bool isConstructCall, 57 | 58 | _In_ JsValueRef *arguments, 59 | 60 | _In_ unsigned short argumentCount, 61 | 62 | _In_opt_ void *callbackState 63 | ) 64 | { 65 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 66 | 67 | JsValueRef result = nullptr; 68 | 69 | JsErrorCode errorCode = JsErrorFatal; 70 | 71 | HRESULT hr = E_FAIL; 72 | 73 | ULONG64 offset = 0; 74 | 75 | do 76 | { 77 | hr = pthis->m_debugSystemObjects2->GetImplicitThreadDataOffset(&offset); 78 | if ( !SUCCEEDED(hr) ) 79 | { 80 | JsExThrowError("GetImplicitThreadDataOffset fail 0x%08X" , hr); 81 | break ; 82 | } 83 | 84 | JsExCreateUint64( offset , &result); 85 | 86 | } while (false); 87 | 88 | return result; 89 | } 90 | 91 | 92 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::SetImplicitProcessDataOffset( 93 | 94 | _In_ JsValueRef callee, 95 | 96 | _In_ bool isConstructCall, 97 | 98 | _In_ JsValueRef *arguments, 99 | 100 | _In_ unsigned short argumentCount, 101 | 102 | _In_opt_ void *callbackState 103 | ) 104 | { 105 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 106 | 107 | JsValueRef result = nullptr; 108 | 109 | JsErrorCode errorCode = JsErrorFatal; 110 | 111 | HRESULT hr = E_FAIL; 112 | 113 | uint64_t arg1Offset = 0; 114 | 115 | 116 | do 117 | { 118 | if ( argumentCount < 2 ) 119 | { 120 | JsExThrowError("invalid argument cound %d" , argumentCount); 121 | break; 122 | } 123 | 124 | errorCode = JsExAssumeUint64( arguments[1] , &arg1Offset ); 125 | if ( JsNoError != errorCode ) 126 | { 127 | JsExThrowError("assume offset fail 0x%08X" , errorCode); 128 | break; 129 | } 130 | 131 | hr = pthis->m_debugSystemObjects2->SetImplicitProcessDataOffset(arg1Offset); 132 | if ( SUCCEEDED(hr) ) 133 | { 134 | JsBoolToBoolean(true , &result); 135 | } 136 | else 137 | { 138 | JsBoolToBoolean(false , &result); 139 | } 140 | 141 | 142 | } while (false); 143 | 144 | return result; 145 | } 146 | 147 | _Ret_maybenull_ JsValueRef CALLBACK BindingDbgEng::SetImplicitThreadDataOffset( 148 | 149 | _In_ JsValueRef callee, 150 | 151 | _In_ bool isConstructCall, 152 | 153 | _In_ JsValueRef *arguments, 154 | 155 | _In_ unsigned short argumentCount, 156 | 157 | _In_opt_ void *callbackState 158 | ) 159 | { 160 | BindingDbgEng *pthis = (BindingDbgEng *)(callbackState); 161 | 162 | JsValueRef result = nullptr; 163 | 164 | JsErrorCode errorCode = JsErrorFatal; 165 | 166 | HRESULT hr = E_FAIL; 167 | 168 | uint64_t arg1Offset = 0; 169 | 170 | 171 | do 172 | { 173 | if ( argumentCount < 2 ) 174 | { 175 | JsExThrowError("invalid argument cound %d" , argumentCount); 176 | break; 177 | } 178 | 179 | errorCode = JsExAssumeUint64( arguments[1] , &arg1Offset ); 180 | if ( JsNoError != errorCode ) 181 | { 182 | JsExThrowError("assume offset fail 0x%08X" , errorCode); 183 | break; 184 | } 185 | 186 | hr = pthis->m_debugSystemObjects2->SetImplicitThreadDataOffset(arg1Offset); 187 | if ( SUCCEEDED(hr) ) 188 | { 189 | JsBoolToBoolean(true , &result); 190 | } 191 | else 192 | { 193 | JsBoolToBoolean(false , &result); 194 | } 195 | 196 | } while (false); 197 | 198 | return result; 199 | } -------------------------------------------------------------------------------- /src/callbacks/captured_output_callbacks.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file captured_output_callbacks.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "captured_output_callbacks.h" 10 | 11 | CapturedOutputCallbacks::CapturedOutputCallbacks() 12 | { 13 | this->m_refs = 1; 14 | } 15 | 16 | CapturedOutputCallbacks::~CapturedOutputCallbacks() 17 | { 18 | } 19 | 20 | std::string CapturedOutputCallbacks::GetCapturedText() 21 | { 22 | return this->m_text; 23 | } 24 | 25 | HRESULT __stdcall CapturedOutputCallbacks::QueryInterface(_In_ REFIID InterfaceId, _Out_ PVOID *ppvObject) 26 | { 27 | HRESULT hr = E_FAIL; 28 | 29 | HRESULT result = E_FAIL; 30 | 31 | do 32 | { 33 | if (nullptr == ppvObject) 34 | { 35 | result = E_INVALIDARG; 36 | break; 37 | } 38 | 39 | if (IsEqualIID(InterfaceId, IID_IUnknown)) 40 | { 41 | this->AddRef(); 42 | *ppvObject = this; 43 | } 44 | else if (IsEqualIID(InterfaceId, IID_IDebugOutputCallbacks)) 45 | { 46 | this->AddRef(); 47 | *ppvObject = this; 48 | } 49 | else 50 | { 51 | result = E_NOTIMPL; 52 | break; 53 | } 54 | 55 | result = S_OK; 56 | 57 | } while (false); 58 | 59 | return result; 60 | } 61 | 62 | ULONG __stdcall CapturedOutputCallbacks::AddRef() 63 | { 64 | return InterlockedIncrement(&this->m_refs); 65 | } 66 | 67 | ULONG __stdcall CapturedOutputCallbacks::Release() 68 | { 69 | ULONG refs = InterlockedDecrement(&this->m_refs); 70 | 71 | if (0 == refs) 72 | { 73 | delete this; 74 | } 75 | 76 | return refs; 77 | } 78 | 79 | HRESULT __stdcall CapturedOutputCallbacks::Output(_In_ ULONG Mask, _In_ PCSTR Text) 80 | { 81 | do 82 | { 83 | if (nullptr == Text) 84 | { 85 | break; 86 | } 87 | 88 | this->m_text += std::string( Text); 89 | 90 | } while (false); 91 | 92 | return S_OK; 93 | } -------------------------------------------------------------------------------- /src/callbacks/captured_output_callbacks.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file captured_output_callbacks.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_CAPTURED_OUTPUT_CALLBACKS_HEADER_FILE__ 10 | #define __MY_CAPTURED_OUTPUT_CALLBACKS_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include "precompile.h" 14 | 15 | class CapturedOutputCallbacks : public IDebugOutputCallbacks 16 | { 17 | public: 18 | CapturedOutputCallbacks(); 19 | 20 | ~CapturedOutputCallbacks(); 21 | 22 | 23 | public: 24 | 25 | 26 | std::string GetCapturedText(); 27 | 28 | 29 | public: 30 | // IUnknown. 31 | HRESULT __stdcall QueryInterface(_In_ REFIID InterfaceId, _Out_ PVOID *ppvObject); 32 | 33 | ULONG __stdcall AddRef(); 34 | 35 | ULONG __stdcall Release(); 36 | 37 | public: 38 | // IDebugOutputCallbacks. 39 | 40 | HRESULT __stdcall Output(_In_ ULONG Mask, _In_ PCSTR Text); 41 | 42 | private: 43 | 44 | ULONG m_refs; 45 | 46 | protected: 47 | 48 | std::string m_text; 49 | }; 50 | 51 | //////////////////////////////////////////////////// 52 | #endif //__MY_CAPTURED_OUTPUT_CALLBACKS_HEADER_FILE__ 53 | -------------------------------------------------------------------------------- /src/callbacks/standard_event_callbacks.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file standard_event_callbacks.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "standard_event_callbacks.h" 10 | 11 | StandardEventCallbacks::StandardEventCallbacks() 12 | { 13 | this->m_refs = 1; 14 | } 15 | 16 | StandardEventCallbacks::~StandardEventCallbacks() 17 | { 18 | } 19 | 20 | HRESULT __stdcall StandardEventCallbacks::QueryInterface(_In_ REFIID InterfaceId, _Out_ PVOID *ppvObject) 21 | { 22 | HRESULT hr = E_FAIL; 23 | 24 | HRESULT result = E_FAIL; 25 | 26 | do 27 | { 28 | if (nullptr == ppvObject) 29 | { 30 | result = E_INVALIDARG; 31 | break; 32 | } 33 | 34 | if (IsEqualIID(InterfaceId, IID_IUnknown)) 35 | { 36 | this->AddRef(); 37 | *ppvObject = this; 38 | } 39 | else if (IsEqualIID(InterfaceId, IID_IDebugEventCallbacks)) 40 | { 41 | this->AddRef(); 42 | *ppvObject = this; 43 | } 44 | else 45 | { 46 | result = E_NOTIMPL; 47 | break; 48 | } 49 | 50 | result = S_OK; 51 | 52 | } while (false); 53 | 54 | return result; 55 | } 56 | 57 | ULONG __stdcall StandardEventCallbacks::AddRef() 58 | { 59 | return InterlockedIncrement(&this->m_refs); 60 | } 61 | 62 | ULONG __stdcall StandardEventCallbacks::Release() 63 | { 64 | ULONG refs = InterlockedDecrement(&this->m_refs); 65 | 66 | if (0 == refs) 67 | { 68 | delete this; 69 | } 70 | 71 | return refs; 72 | } 73 | 74 | // The engine calls GetInterestMask once when 75 | // the event callbacks are set for a client. 76 | HRESULT __stdcall StandardEventCallbacks::GetInterestMask(_Out_ PULONG Mask) 77 | { 78 | HRESULT result = E_FAIL; 79 | 80 | HRESULT hr = E_FAIL; 81 | 82 | ULONG interestMask = 0; 83 | 84 | do 85 | { 86 | interestMask |= DEBUG_EVENT_BREAKPOINT; 87 | 88 | interestMask |= DEBUG_EVENT_EXCEPTION; 89 | 90 | interestMask |= DEBUG_EVENT_CREATE_THREAD; 91 | 92 | interestMask |= DEBUG_EVENT_EXIT_THREAD; 93 | 94 | interestMask |= DEBUG_EVENT_CREATE_PROCESS; 95 | 96 | interestMask |= DEBUG_EVENT_EXIT_PROCESS; 97 | 98 | interestMask |= DEBUG_EVENT_LOAD_MODULE; 99 | 100 | interestMask |= DEBUG_EVENT_UNLOAD_MODULE; 101 | 102 | interestMask |= DEBUG_EVENT_SYSTEM_ERROR; 103 | 104 | interestMask |= DEBUG_EVENT_SESSION_STATUS; 105 | 106 | interestMask |= DEBUG_EVENT_CHANGE_DEBUGGEE_STATE; 107 | 108 | interestMask |= DEBUG_EVENT_CHANGE_ENGINE_STATE; 109 | 110 | interestMask |= DEBUG_EVENT_CHANGE_SYMBOL_STATE; 111 | 112 | interestMask |= DEBUG_EVENT_SERVICE_EXCEPTION; 113 | 114 | result = S_OK; 115 | 116 | } while (false); 117 | 118 | return result; 119 | } 120 | 121 | // A breakpoint event is generated when 122 | // a breakpoint exception is received and 123 | // it can be mapped to an existing breakpoint. 124 | // The callback method is given a reference 125 | // to the breakpoint and should release it when 126 | // it is done with it. 127 | HRESULT __stdcall StandardEventCallbacks::Breakpoint(_In_ PDEBUG_BREAKPOINT Bp) 128 | { 129 | HRESULT result = E_FAIL; 130 | 131 | HRESULT hr = E_FAIL; 132 | 133 | do 134 | { 135 | 136 | result = S_OK; 137 | 138 | } while (false); 139 | 140 | return result; 141 | } 142 | 143 | // Exceptions include breaks which cannot 144 | // be mapped to an existing breakpoint 145 | // instance. 146 | HRESULT __stdcall StandardEventCallbacks::Exception(_In_ PEXCEPTION_RECORD64 Exception, _In_ ULONG FirstChance) 147 | { 148 | HRESULT result = E_FAIL; 149 | 150 | HRESULT hr = E_FAIL; 151 | 152 | do 153 | { 154 | 155 | result = S_OK; 156 | 157 | } while (false); 158 | 159 | return result; 160 | } 161 | 162 | // Any of these values can be zero if they 163 | // cannot be provided by the engine. 164 | // Currently the kernel does not return thread 165 | // or process change events. 166 | HRESULT __stdcall StandardEventCallbacks::CreateThread(_In_ ULONG64 Handle, _In_ ULONG64 DataOffset, 167 | _In_ ULONG64 StartOffset) 168 | { 169 | HRESULT result = E_FAIL; 170 | 171 | HRESULT hr = E_FAIL; 172 | 173 | do 174 | { 175 | 176 | result = S_OK; 177 | 178 | } while (false); 179 | 180 | return result; 181 | } 182 | 183 | HRESULT __stdcall StandardEventCallbacks::ExitThread(_In_ ULONG ExitCode) 184 | { 185 | HRESULT result = E_FAIL; 186 | 187 | HRESULT hr = E_FAIL; 188 | 189 | do 190 | { 191 | 192 | result = S_OK; 193 | 194 | } while (false); 195 | 196 | return result; 197 | } 198 | 199 | // Any of these values can be zero if they 200 | // cannot be provided by the engine. 201 | HRESULT __stdcall StandardEventCallbacks::CreateProcess(_In_ ULONG64 ImageFileHandle, _In_ ULONG64 Handle, 202 | _In_ ULONG64 BaseOffset, _In_ ULONG ModuleSize, 203 | _In_opt_ PCSTR ModuleName, _In_opt_ PCSTR ImageName, 204 | _In_ ULONG CheckSum, _In_ ULONG TimeDateStamp, 205 | _In_ ULONG64 InitialThreadHandle, _In_ ULONG64 ThreadDataOffset, 206 | _In_ ULONG64 StartOffset) 207 | { 208 | HRESULT result = E_FAIL; 209 | 210 | HRESULT hr = E_FAIL; 211 | 212 | do 213 | { 214 | 215 | result = S_OK; 216 | 217 | } while (false); 218 | 219 | return result; 220 | } 221 | 222 | _Analysis_noreturn_ HRESULT __stdcall StandardEventCallbacks::ExitProcess(_In_ ULONG ExitCode) 223 | { 224 | HRESULT result = E_FAIL; 225 | 226 | HRESULT hr = E_FAIL; 227 | 228 | do 229 | { 230 | 231 | result = S_OK; 232 | 233 | } while (false); 234 | 235 | return result; 236 | } 237 | 238 | // Any of these values may be zero. 239 | HRESULT __stdcall StandardEventCallbacks::LoadModule(_In_ ULONG64 ImageFileHandle, _In_ ULONG64 BaseOffset, 240 | _In_ ULONG ModuleSize, _In_opt_ PCSTR ModuleName, 241 | _In_opt_ PCSTR ImageName, _In_ ULONG CheckSum, 242 | _In_ ULONG TimeDateStamp) 243 | { 244 | HRESULT result = E_FAIL; 245 | 246 | HRESULT hr = E_FAIL; 247 | 248 | do 249 | { 250 | 251 | result = S_OK; 252 | 253 | } while (false); 254 | 255 | return result; 256 | } 257 | 258 | HRESULT __stdcall StandardEventCallbacks::UnloadModule(_In_opt_ PCSTR ImageBaseName, _In_ ULONG64 BaseOffset) 259 | { 260 | HRESULT result = E_FAIL; 261 | 262 | HRESULT hr = E_FAIL; 263 | 264 | do 265 | { 266 | 267 | result = S_OK; 268 | 269 | } while (false); 270 | 271 | return result; 272 | } 273 | 274 | HRESULT __stdcall StandardEventCallbacks::SystemError(_In_ ULONG Error, _In_ ULONG Level) 275 | { 276 | HRESULT result = E_FAIL; 277 | 278 | HRESULT hr = E_FAIL; 279 | 280 | do 281 | { 282 | 283 | result = S_OK; 284 | 285 | } while (false); 286 | 287 | return result; 288 | } 289 | 290 | // Session status is synchronous like the other 291 | // wait callbacks but it is called as the state 292 | // of the session is changing rather than at 293 | // specific events so its return value does not 294 | // influence waiting. Implementations should just 295 | // return DEBUG_STATUS_NO_CHANGE. 296 | // Also, because some of the status 297 | // notifications are very early or very 298 | // late in the session lifetime there may not be 299 | // current processes or threads when the notification 300 | // is generated. 301 | HRESULT __stdcall StandardEventCallbacks::SessionStatus(_In_ ULONG Status) 302 | { 303 | HRESULT result = E_FAIL; 304 | 305 | HRESULT hr = E_FAIL; 306 | 307 | do 308 | { 309 | 310 | result = S_OK; 311 | 312 | } while (false); 313 | 314 | return result; 315 | } 316 | 317 | // The following callbacks are informational 318 | // callbacks notifying the provider about 319 | // changes in debug state. The return value 320 | // of these callbacks is ignored. Implementations 321 | // can not call back into the engine. 322 | 323 | // Debuggee state, such as registers or data spaces, 324 | // has changed. 325 | HRESULT __stdcall StandardEventCallbacks::ChangeDebuggeeState(_In_ ULONG Flags, _In_ ULONG64 Argument) 326 | { 327 | HRESULT result = E_FAIL; 328 | 329 | HRESULT hr = E_FAIL; 330 | 331 | do 332 | { 333 | 334 | result = S_OK; 335 | 336 | } while (false); 337 | 338 | return result; 339 | } 340 | 341 | // Engine state has changed. 342 | HRESULT __stdcall StandardEventCallbacks::ChangeEngineState(_In_ ULONG Flags, _In_ ULONG64 Argument) 343 | { 344 | HRESULT result = E_FAIL; 345 | 346 | HRESULT hr = E_FAIL; 347 | 348 | do 349 | { 350 | 351 | result = S_OK; 352 | 353 | } while (false); 354 | 355 | return result; 356 | } 357 | 358 | // Symbol state has changed. 359 | HRESULT __stdcall StandardEventCallbacks::ChangeSymbolState(_In_ ULONG Flags, _In_ ULONG64 Argument) 360 | { 361 | HRESULT result = E_FAIL; 362 | 363 | HRESULT hr = E_FAIL; 364 | 365 | do 366 | { 367 | 368 | result = S_OK; 369 | 370 | } while (false); 371 | 372 | return result; 373 | } 374 | -------------------------------------------------------------------------------- /src/callbacks/standard_event_callbacks.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file standard_event_callbacks.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_STANDARD_EVENT_CALLBACKS_HEADER_FILE__ 10 | #define __MY_STANDARD_EVENT_CALLBACKS_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include "precompile.h" 14 | 15 | class StandardEventCallbacks : public IDebugEventCallbacks 16 | { 17 | public: 18 | StandardEventCallbacks(); 19 | 20 | ~StandardEventCallbacks(); 21 | 22 | public: 23 | // IUnknown. 24 | HRESULT __stdcall QueryInterface(_In_ REFIID InterfaceId, _Out_ PVOID *ppvObject); 25 | 26 | ULONG __stdcall AddRef(); 27 | 28 | ULONG __stdcall Release(); 29 | 30 | public: 31 | // IDebugEventCallbacks. 32 | 33 | // The engine calls GetInterestMask once when 34 | // the event callbacks are set for a client. 35 | HRESULT __stdcall GetInterestMask(_Out_ PULONG Mask); 36 | 37 | // A breakpoint event is generated when 38 | // a breakpoint exception is received and 39 | // it can be mapped to an existing breakpoint. 40 | // The callback method is given a reference 41 | // to the breakpoint and should release it when 42 | // it is done with it. 43 | HRESULT __stdcall Breakpoint(_In_ PDEBUG_BREAKPOINT Bp); 44 | 45 | // Exceptions include breaks which cannot 46 | // be mapped to an existing breakpoint 47 | // instance. 48 | HRESULT __stdcall Exception(_In_ PEXCEPTION_RECORD64 Exception, _In_ ULONG FirstChance); 49 | 50 | // Any of these values can be zero if they 51 | // cannot be provided by the engine. 52 | // Currently the kernel does not return thread 53 | // or process change events. 54 | HRESULT __stdcall CreateThread(_In_ ULONG64 Handle, _In_ ULONG64 DataOffset, _In_ ULONG64 StartOffset); 55 | 56 | HRESULT __stdcall ExitThread(_In_ ULONG ExitCode); 57 | 58 | // Any of these values can be zero if they 59 | // cannot be provided by the engine. 60 | HRESULT __stdcall CreateProcess(_In_ ULONG64 ImageFileHandle, _In_ ULONG64 Handle, _In_ ULONG64 BaseOffset, 61 | _In_ ULONG ModuleSize, _In_opt_ PCSTR ModuleName, _In_opt_ PCSTR ImageName, 62 | _In_ ULONG CheckSum, _In_ ULONG TimeDateStamp, _In_ ULONG64 InitialThreadHandle, 63 | _In_ ULONG64 ThreadDataOffset, _In_ ULONG64 StartOffset); 64 | 65 | _Analysis_noreturn_ HRESULT __stdcall ExitProcess(_In_ ULONG ExitCode); 66 | 67 | // Any of these values may be zero. 68 | HRESULT __stdcall LoadModule(_In_ ULONG64 ImageFileHandle, _In_ ULONG64 BaseOffset, _In_ ULONG ModuleSize, 69 | _In_opt_ PCSTR ModuleName, _In_opt_ PCSTR ImageName, _In_ ULONG CheckSum, 70 | _In_ ULONG TimeDateStamp); 71 | 72 | HRESULT __stdcall UnloadModule(_In_opt_ PCSTR ImageBaseName, _In_ ULONG64 BaseOffset); 73 | 74 | HRESULT __stdcall SystemError(_In_ ULONG Error, _In_ ULONG Level); 75 | 76 | // Session status is synchronous like the other 77 | // wait callbacks but it is called as the state 78 | // of the session is changing rather than at 79 | // specific events so its return value does not 80 | // influence waiting. Implementations should just 81 | // return DEBUG_STATUS_NO_CHANGE. 82 | // Also, because some of the status 83 | // notifications are very early or very 84 | // late in the session lifetime there may not be 85 | // current processes or threads when the notification 86 | // is generated. 87 | HRESULT __stdcall SessionStatus(_In_ ULONG Status); 88 | 89 | // The following callbacks are informational 90 | // callbacks notifying the provider about 91 | // changes in debug state. The return value 92 | // of these callbacks is ignored. Implementations 93 | // can not call back into the engine. 94 | 95 | // Debuggee state, such as registers or data spaces, 96 | // has changed. 97 | HRESULT __stdcall ChangeDebuggeeState(_In_ ULONG Flags, _In_ ULONG64 Argument); 98 | 99 | // Engine state has changed. 100 | HRESULT __stdcall ChangeEngineState(_In_ ULONG Flags, _In_ ULONG64 Argument); 101 | 102 | // Symbol state has changed. 103 | HRESULT __stdcall ChangeSymbolState(_In_ ULONG Flags, _In_ ULONG64 Argument); 104 | 105 | private: 106 | ULONG m_refs; 107 | 108 | private: 109 | IDebugClient *m_debugClient; 110 | }; 111 | 112 | //////////////////////////////////////////////////// 113 | #endif //__MY_STANDARD_EVENT_CALLBACKS_HEADER_FILE__ 114 | -------------------------------------------------------------------------------- /src/callbacks/standard_output_callbacks.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file standard_output_callbacks.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "standard_output_callbacks.h" 10 | 11 | StandardOutputCallbacks::StandardOutputCallbacks() 12 | { 13 | this->m_refs = 1; 14 | } 15 | 16 | StandardOutputCallbacks::~StandardOutputCallbacks() 17 | { 18 | } 19 | 20 | HRESULT __stdcall StandardOutputCallbacks::QueryInterface(_In_ REFIID InterfaceId, _Out_ PVOID *ppvObject) 21 | { 22 | HRESULT hr = E_FAIL; 23 | 24 | HRESULT result = E_FAIL; 25 | 26 | do 27 | { 28 | if (nullptr == ppvObject) 29 | { 30 | result = E_INVALIDARG; 31 | break; 32 | } 33 | 34 | if (IsEqualIID(InterfaceId, IID_IUnknown)) 35 | { 36 | this->AddRef(); 37 | *ppvObject = this; 38 | } 39 | else if (IsEqualIID(InterfaceId, IID_IDebugOutputCallbacks)) 40 | { 41 | this->AddRef(); 42 | *ppvObject = this; 43 | } 44 | else 45 | { 46 | result = E_NOTIMPL; 47 | break; 48 | } 49 | 50 | result = S_OK; 51 | 52 | } while (false); 53 | 54 | return result; 55 | } 56 | 57 | ULONG __stdcall StandardOutputCallbacks::AddRef() 58 | { 59 | return InterlockedIncrement(&this->m_refs); 60 | } 61 | 62 | ULONG __stdcall StandardOutputCallbacks::Release() 63 | { 64 | ULONG refs = InterlockedDecrement(&this->m_refs); 65 | 66 | if (0 == refs) 67 | { 68 | delete this; 69 | } 70 | 71 | return refs; 72 | } 73 | 74 | HRESULT __stdcall StandardOutputCallbacks::Output(_In_ ULONG Mask, _In_ PCSTR Text) 75 | { 76 | do 77 | { 78 | if (nullptr == Text) 79 | { 80 | break; 81 | } 82 | 83 | printf("%s", Text); 84 | 85 | } while (false); 86 | 87 | return S_OK; 88 | } -------------------------------------------------------------------------------- /src/callbacks/standard_output_callbacks.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file standard_output_callbacks.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_STANDARD_OUTPUT_CALLBACKS_HEADER_FILE__ 10 | #define __MY_STANDARD_OUTPUT_CALLBACKS_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include "precompile.h" 14 | 15 | class StandardOutputCallbacks : public IDebugOutputCallbacks 16 | { 17 | public: 18 | StandardOutputCallbacks(); 19 | 20 | ~StandardOutputCallbacks(); 21 | 22 | public: 23 | // IUnknown. 24 | HRESULT __stdcall QueryInterface(_In_ REFIID InterfaceId, _Out_ PVOID *ppvObject); 25 | 26 | ULONG __stdcall AddRef(); 27 | 28 | ULONG __stdcall Release(); 29 | 30 | public: 31 | // IDebugOutputCallbacks. 32 | 33 | HRESULT __stdcall Output(_In_ ULONG Mask, _In_ PCSTR Text); 34 | 35 | private: 36 | ULONG m_refs; 37 | }; 38 | 39 | //////////////////////////////////////////////////// 40 | #endif //__MY_STANDARD_OUTPUT_CALLBACKS_HEADER_FILE__ 41 | -------------------------------------------------------------------------------- /src/command/commands.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file commands.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_COMMANDS_HEADER_FILE__ 10 | #define __MY_COMMANDS_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include "precompile.h" 14 | 15 | EXTERN_C HRESULT __stdcall jshelp(IDebugClient *debugClient, const char *cmdline); 16 | 17 | EXTERN_C HRESULT __stdcall jscall(IDebugClient *debugClient, const char *cmdline); 18 | 19 | EXTERN_C HRESULT __stdcall jsrun(IDebugClient *debugClient, const char *cmdline); 20 | 21 | EXTERN_C HRESULT __stdcall jsload(IDebugClient *debugClient, const char *cmdline); 22 | 23 | EXTERN_C HRESULT __stdcall jsunload(IDebugClient *debugClient, const char *cmdline); 24 | 25 | 26 | EXTERN_C HRESULT __stdcall jslist(IDebugClient *debugClient, const char *cmdline); 27 | 28 | EXTERN_C HRESULT __stdcall jsclear(IDebugClient *debugClient, const char *cmdline); 29 | 30 | //////////////////////////////////////////////////// 31 | #endif //__MY_COMMANDS_HEADER_FILE__ 32 | -------------------------------------------------------------------------------- /src/command/jscall.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmd_jscall.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "src/extension.h" 12 | 13 | #include "util/util_string.h" 14 | 15 | // jscall filename routine 16 | EXTERN_C HRESULT __stdcall jscall(IDebugClient *debugClient, const char *cmdline) 17 | { 18 | HRESULT finalResult = E_FAIL; 19 | 20 | HRESULT hr = E_FAIL; 21 | 22 | JsValueRef exports = nullptr; 23 | 24 | JsErrorCode errorCode = JsErrorFatal; 25 | 26 | JsValueRef routineValue = nullptr; 27 | 28 | Extension *extension = Extension::GetInstance(); 29 | 30 | std::vector argv = UtilCmdlineToArgv(cmdline); 31 | 32 | std::string filename; 33 | 34 | std::string routineName; 35 | 36 | do 37 | { 38 | UNREFERENCED_PARAMETER(debugClient); 39 | 40 | if (argv.size() < 2) 41 | { 42 | extension->m_pod->DebugPrintf("[jswd] invalid usage of jscall , use !js.help for help.\n"); 43 | break; 44 | } 45 | 46 | filename = std::string( argv[0] ); 47 | argv.erase(argv.begin() ); 48 | 49 | 50 | exports = extension->FindScript(filename); 51 | if (nullptr == exports ) 52 | { 53 | extension->m_pod->DebugPrintf("[jswd] not found loaded script \"%s\".\n" , filename.c_str() ); 54 | break ; 55 | } 56 | 57 | routineName = argv[0]; 58 | argv.erase(argv.begin() ); 59 | 60 | errorCode = JsExGetProperty(exports, routineName, true, &routineValue); 61 | if (JsNoError == errorCode) 62 | { 63 | JsExCallWithStringArguments(nullptr, routineValue, argv, nullptr); 64 | } 65 | else 66 | { 67 | extension->m_pod->DebugPrintf("[jswd] not found routine \"%s\" in loaded script \"%s\" ok.\n" , routineName.c_str() , filename.c_str() ); 68 | } 69 | 70 | finalResult = S_OK; 71 | 72 | } while (false); 73 | 74 | return finalResult; 75 | } 76 | -------------------------------------------------------------------------------- /src/command/jsclear.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmd_jsclear.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "src/extension.h" 12 | 13 | #include "util/util_string.h" 14 | 15 | EXTERN_C [[maybe_unused]] HRESULT __stdcall jsclear(IDebugClient *debugClient, const char *cmdline) 16 | { 17 | HRESULT finalResult = E_FAIL; 18 | 19 | JsErrorCode errorCode = JsErrorFatal; 20 | 21 | Extension *extension = Extension::GetInstance(); 22 | 23 | std::map::iterator it; 24 | 25 | std::string filename; 26 | 27 | JsValueRef exports = nullptr; 28 | 29 | JsValueRef routine = nullptr; 30 | 31 | do 32 | { 33 | UNREFERENCED_PARAMETER(debugClient); 34 | 35 | for ( it = extension->m_scripts.begin(); it != extension->m_scripts.end(); it++ ) 36 | { 37 | filename = it->first; 38 | 39 | exports = it->second; 40 | 41 | 42 | routine = nullptr; 43 | errorCode = JsExGetProperty(exports, "unload", true, &routine); 44 | if (JsNoError == errorCode) 45 | { 46 | JsExCall(nullptr, routine, nullptr); 47 | } 48 | 49 | extension->m_pod->DebugPrintf("[jswd] unload script \"%s\" ok.\n" , filename.c_str() ); 50 | 51 | JsRelease(exports , nullptr); 52 | } 53 | 54 | extension->m_scripts.clear(); 55 | 56 | extension->m_pod->DebugPrintf("[jswd] all loaded scripts clear."); 57 | 58 | finalResult = S_OK; 59 | 60 | } while (false); 61 | 62 | return finalResult; 63 | } 64 | -------------------------------------------------------------------------------- /src/command/jshelp.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmd_jshep.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "src/extension.h" 12 | 13 | #include "util/util_string.h" 14 | 15 | #include "version.h" 16 | 17 | EXTERN_C HRESULT __stdcall jshelp(IDebugClient *debugClient, const char *cmdline) 18 | { 19 | Extension *extension = Extension::GetInstance(); 20 | 21 | UNREFERENCED_PARAMETER(debugClient); 22 | 23 | extension->printUsage(); 24 | 25 | return S_OK; 26 | } 27 | -------------------------------------------------------------------------------- /src/command/jslist.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmd_jslist.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "src/extension.h" 12 | 13 | #include "util/util_string.h" 14 | 15 | EXTERN_C HRESULT __stdcall jslist(IDebugClient *debugClient, const char *cmdline) 16 | { 17 | HRESULT finalResult = E_FAIL; 18 | 19 | JsErrorCode errorCode = JsErrorFatal; 20 | 21 | Extension *extension = Extension::GetInstance(); 22 | 23 | std::vector argv = UtilCmdlineToArgv(cmdline); 24 | 25 | std::map::iterator it; 26 | 27 | std::string filename; 28 | 29 | int i = 0; 30 | 31 | 32 | do 33 | { 34 | UNREFERENCED_PARAMETER(debugClient); 35 | 36 | extension->m_pod->DebugPrintf("[jswd] there are %d scripts.\n" , extension->m_scripts.size() ); 37 | 38 | for ( it = extension->m_scripts.begin(); it != extension->m_scripts.end(); it++ ) 39 | { 40 | filename = it->first; 41 | 42 | extension->m_pod->DebugPrintf("[%d] -> %s\n" , i , filename.c_str() ); 43 | 44 | i++; 45 | } 46 | 47 | finalResult = S_OK; 48 | 49 | } while (false); 50 | 51 | return finalResult; 52 | } 53 | -------------------------------------------------------------------------------- /src/command/jsload.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmd_jsload.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "src/extension.h" 12 | 13 | #include "util/util_string.h" 14 | 15 | EXTERN_C HRESULT __stdcall jsload(IDebugClient *debugClient, const char *cmdline) 16 | { 17 | HRESULT finalResult = E_FAIL; 18 | 19 | HRESULT hr = E_FAIL; 20 | 21 | JsValueRef exports = nullptr; 22 | 23 | JsErrorCode errorCode = JsErrorFatal; 24 | 25 | JsValueRef routine = nullptr; 26 | 27 | Extension *extension = Extension::GetInstance(); 28 | 29 | std::vector argv = UtilCmdlineToArgv(cmdline); 30 | 31 | std::string filename; 32 | 33 | do 34 | { 35 | UNREFERENCED_PARAMETER(debugClient); 36 | 37 | if (argv.size() <= 0) 38 | { 39 | extension->m_pod->DebugPrintf("[jswd] invalid usage of jscall , use !js.help for help.\n"); 40 | break; 41 | } 42 | 43 | filename = argv[0]; 44 | 45 | exports = extension->FindScript(filename); 46 | if (nullptr != exports ) 47 | { 48 | extension->m_pod->DebugPrintf("[jswd] script \"%s\" is already loaded.\n" , filename.c_str() ); 49 | break; 50 | } 51 | 52 | errorCode = extension->m_pod->RequireModule(filename, &exports); 53 | if (JsNoError != errorCode) 54 | { 55 | extension->m_pod->PrintException(); 56 | break; 57 | } 58 | 59 | if ( !extension->AddScript(filename, exports) ) 60 | { 61 | extension->m_pod->DebugPrintf("[jswd] script \"%s\" is already loaded.\n" , filename.c_str() ); 62 | break; 63 | } 64 | 65 | errorCode = JsExGetProperty(exports, "load", true, &routine); 66 | if (JsNoError == errorCode) 67 | { 68 | JsExCall(nullptr, routine, nullptr); 69 | } 70 | 71 | extension->m_pod->DebugPrintf("[jswd] load script \"%s\" ok.\n" , filename.c_str() ); 72 | 73 | finalResult = S_OK; 74 | 75 | } while (false); 76 | 77 | return finalResult; 78 | } 79 | -------------------------------------------------------------------------------- /src/command/jsrun.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmd_jsrun.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "src/extension.h" 12 | 13 | #include "util/util_string.h" 14 | 15 | EXTERN_C HRESULT __stdcall jsrun(IDebugClient *debugClient, const char *cmdline) 16 | { 17 | HRESULT finalResult = E_FAIL; 18 | 19 | HRESULT hr = E_FAIL; 20 | 21 | JsValueRef exports = nullptr; 22 | 23 | JsErrorCode errorCode = JsErrorFatal; 24 | 25 | JsValueRef routine = nullptr; 26 | 27 | Extension *extension = Extension::GetInstance(); 28 | 29 | std::vector argv = UtilCmdlineToArgv(cmdline); 30 | 31 | std::string filename; 32 | 33 | do 34 | { 35 | UNREFERENCED_PARAMETER(debugClient); 36 | 37 | if (argv.size() <= 0) 38 | { 39 | extension->m_pod->DebugPrintf("[jswd] invalid usage of jscall , use !js.help for help.\n"); 40 | break; 41 | } 42 | 43 | filename = argv[0]; 44 | 45 | errorCode = extension->m_pod->RequireModule(filename, &exports); 46 | if (JsNoError != errorCode) 47 | { 48 | extension->m_pod->PrintException(); 49 | break; 50 | } 51 | 52 | errorCode = JsExGetProperty(exports, "main", true, &routine); 53 | if (JsNoError == errorCode) 54 | { 55 | errorCode = JsExCallWithStringArray(nullptr, routine, argv, nullptr); 56 | if (JsNoError != errorCode) 57 | { 58 | extension->m_pod->PrintException(); 59 | } 60 | } 61 | 62 | 63 | finalResult = S_OK; 64 | 65 | } while (false); 66 | 67 | return finalResult; 68 | } 69 | -------------------------------------------------------------------------------- /src/command/jsunload.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmd_jsunload.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "src/extension.h" 12 | 13 | #include "util/util_string.h" 14 | 15 | EXTERN_C HRESULT __stdcall jsunload(IDebugClient *debugClient, const char *cmdline) 16 | { 17 | HRESULT finalResult = E_FAIL; 18 | 19 | JsValueRef exports = nullptr; 20 | 21 | JsErrorCode errorCode = JsErrorFatal; 22 | 23 | JsValueRef routine = nullptr; 24 | 25 | Extension *extension = Extension::GetInstance(); 26 | 27 | std::vector argv = UtilCmdlineToArgv(cmdline); 28 | 29 | std::string filename; 30 | 31 | do 32 | { 33 | UNREFERENCED_PARAMETER(debugClient); 34 | 35 | if (argv.size() <= 0) 36 | { 37 | extension->m_pod->DebugPrintf("[jswd] invalid usage of jsunload , use !js.help for help.\n"); 38 | break; 39 | } 40 | 41 | filename = argv[0]; 42 | 43 | exports = extension->RemoveScript(filename); 44 | if (nullptr == exports) 45 | { 46 | extension->m_pod->DebugPrintf("[jswd] not found loaded script \"%s\".\n" , filename.c_str() ); 47 | break; 48 | } 49 | 50 | errorCode = JsExGetProperty(exports, "unload", true, &routine); 51 | if (JsNoError == errorCode) 52 | { 53 | JsExCall(nullptr, routine, nullptr); 54 | } 55 | 56 | JsRelease(exports , nullptr); 57 | 58 | extension->m_pod->DebugPrintf("[jswd] unload script \"%s\" ok.\n" , filename.c_str() ); 59 | 60 | finalResult = S_OK; 61 | 62 | } while (false); 63 | 64 | return finalResult; 65 | } 66 | -------------------------------------------------------------------------------- /src/core/js_pod.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file jswd_pod.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | #include "precompile.h" 9 | 10 | #include "binding/dbgeng/binding_dbgeng.h" 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | 35 | #include "js_pod.h" 36 | 37 | JSPod::JSPod() 38 | { 39 | this->m_runtime = nullptr; 40 | 41 | this->m_context = nullptr; 42 | 43 | this->m_binding = nullptr; 44 | 45 | this->m_builtin = nullptr; 46 | 47 | this->m_nativeRequire = nullptr; 48 | 49 | this->m_moduleRequire = nullptr; 50 | 51 | this->m_output = nullptr; 52 | 53 | /// for dbgeng 54 | 55 | this->m_debugClient = nullptr; 56 | 57 | this->m_debugControl = nullptr; 58 | } 59 | 60 | JSPod::~JSPod() 61 | { 62 | if (nullptr != this->m_runtime) 63 | { 64 | JsSetCurrentContext(JS_INVALID_REFERENCE); 65 | 66 | JsDisposeRuntime(this->m_runtime); 67 | this->m_runtime = nullptr; 68 | } 69 | 70 | if (nullptr != this->m_debugClient) 71 | { 72 | this->m_debugClient->Release(); 73 | this->m_debugClient = nullptr; 74 | } 75 | 76 | if (nullptr != this->m_debugControl) 77 | { 78 | this->m_debugControl->Release(); 79 | this->m_debugControl = nullptr; 80 | } 81 | } 82 | 83 | HRESULT JSPod::Initialize() 84 | { 85 | HRESULT result = E_FAIL; 86 | 87 | HRESULT hr = E_FAIL; 88 | 89 | JsErrorCode errorCode = JsErrorFatal; 90 | 91 | do 92 | { 93 | hr = this->InitializeJSRT(); 94 | if (!SUCCEEDED(hr)) 95 | { 96 | break; 97 | } 98 | 99 | hr = this->InitializeDbgEng(); 100 | if (!SUCCEEDED(hr)) 101 | { 102 | break; 103 | } 104 | 105 | hr = this->SetupBindings(); 106 | if (!SUCCEEDED(hr)) 107 | { 108 | break; 109 | } 110 | 111 | // builtin script 112 | 113 | errorCode = this->m_builtin->RegisterSource( 114 | "dbgeng" , 115 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_DBGENG , SIZEOF_JSWD_BUILTIN_SCRIPT_DBGENG ) 116 | ); 117 | if ( JsNoError != errorCode ) 118 | { 119 | break ; 120 | } 121 | 122 | 123 | 124 | errorCode = this->m_builtin->RegisterSource( 125 | "jswd/module" , 126 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_MODULE , SIZEOF_JSWD_BUILTIN_SCRIPT_MODULE ) 127 | ); 128 | if ( JsNoError != errorCode ) 129 | { 130 | break ; 131 | } 132 | 133 | errorCode = this->m_builtin->RegisterSource( 134 | "jswd/physical" , 135 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_PHYSICAL , SIZEOF_JSWD_BUILTIN_SCRIPT_PHYSICAL ) 136 | ); 137 | if ( JsNoError != errorCode ) 138 | { 139 | break ; 140 | } 141 | 142 | errorCode = this->m_builtin->RegisterSource( 143 | "jswd/processor" , 144 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_PROCESSOR , SIZEOF_JSWD_BUILTIN_SCRIPT_PROCESSOR ) 145 | ); 146 | if ( JsNoError != errorCode ) 147 | { 148 | break ; 149 | } 150 | 151 | errorCode = this->m_builtin->RegisterSource( 152 | "jswd/reader" , 153 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_READER , SIZEOF_JSWD_BUILTIN_SCRIPT_READER ) 154 | ); 155 | if ( JsNoError != errorCode ) 156 | { 157 | break ; 158 | } 159 | 160 | errorCode = this->m_builtin->RegisterSource( 161 | "jswd/register" , 162 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_REGISTER , SIZEOF_JSWD_BUILTIN_SCRIPT_REGISTER ) 163 | ); 164 | if ( JsNoError != errorCode ) 165 | { 166 | break ; 167 | } 168 | 169 | errorCode = this->m_builtin->RegisterSource( 170 | "jswd/segment" , 171 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_SEGMENT , SIZEOF_JSWD_BUILTIN_SCRIPT_SEGMENT ) 172 | ); 173 | if ( JsNoError != errorCode ) 174 | { 175 | break ; 176 | } 177 | 178 | errorCode = this->m_builtin->RegisterSource( 179 | "jswd/symbol" , 180 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_SYMBOL , SIZEOF_JSWD_BUILTIN_SCRIPT_SYMBOL ) 181 | ); 182 | if ( JsNoError != errorCode ) 183 | { 184 | break ; 185 | } 186 | 187 | 188 | errorCode = this->m_builtin->RegisterSource( 189 | "jswd/virtual" , 190 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_VIRTUAL , SIZEOF_JSWD_BUILTIN_SCRIPT_VIRTUAL ) 191 | ); 192 | if ( JsNoError != errorCode ) 193 | { 194 | break ; 195 | } 196 | 197 | errorCode = this->m_builtin->RegisterSource( 198 | "jswd/writer" , 199 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_WRITER , SIZEOF_JSWD_BUILTIN_SCRIPT_WRITER ) 200 | ); 201 | if ( JsNoError != errorCode ) 202 | { 203 | break ; 204 | } 205 | 206 | errorCode = this->m_builtin->RegisterSource( 207 | "jswd" , 208 | std::string( (const char*)JSWD_BUILTIN_SCRIPT_JSWD , SIZEOF_JSWD_BUILTIN_SCRIPT_JSWD ) 209 | ); 210 | if ( JsNoError != errorCode ) 211 | { 212 | break ; 213 | } 214 | 215 | // query real output 216 | hr = this->m_binding->GetValue("stdio", "output", &(this->m_output)); 217 | if (!SUCCEEDED(hr)) 218 | { 219 | break; 220 | } 221 | 222 | hr = this->BootstrapJSRT(); 223 | if (!SUCCEEDED(hr)) 224 | { 225 | this->PrintException(); 226 | break; 227 | } 228 | 229 | result = S_OK; 230 | } while (false); 231 | 232 | return result; 233 | } 234 | 235 | HRESULT JSPod::InitializeJSRT() 236 | { 237 | HRESULT result = E_FAIL; 238 | 239 | JsErrorCode errorCode = JsErrorFatal; 240 | 241 | bool ok = false; 242 | 243 | uint32_t refs = 0; 244 | 245 | do 246 | { 247 | #ifdef _DEBUG 248 | this->m_runtime = JsExCreateRuntime(true); 249 | #else 250 | this->m_runtime = JsExCreateRuntime(false); 251 | #endif //#ifdef _DEBUG 252 | if (nullptr == this->m_runtime) 253 | { 254 | break; 255 | } 256 | 257 | errorCode = JsExCreateContext(this->m_runtime, &(this->m_context)); 258 | if (JsNoError != errorCode) 259 | { 260 | break; 261 | } 262 | 263 | JsAddRef(this->m_context, &refs); 264 | 265 | errorCode = JsSetCurrentContext(this->m_context); 266 | if (JsNoError != errorCode) 267 | { 268 | break; 269 | } 270 | 271 | 272 | 273 | this->m_binding = NativeBinding::Create(); 274 | if (nullptr == this->m_binding) 275 | { 276 | break; 277 | } 278 | 279 | this->m_builtin = NativeBuiltin::Create(); 280 | if (nullptr == this->m_builtin) 281 | { 282 | break; 283 | } 284 | 285 | this->m_nativeRequire = NativeRequire::Create(); 286 | if (nullptr == this->m_nativeRequire) 287 | { 288 | break; 289 | } 290 | 291 | ok = this->m_nativeRequire->RegisterModule("builtin", this->m_builtin->GetHandle()); 292 | if (!ok) 293 | { 294 | break; 295 | } 296 | 297 | ok = this->m_nativeRequire->RegisterModule("binding", this->m_binding->GetHandle()); 298 | if (!ok) 299 | { 300 | break; 301 | } 302 | 303 | #ifdef _DEBUG 304 | errorCode = JsExEnableDebug(); 305 | if (JsNoError != errorCode) 306 | { 307 | break; 308 | } 309 | #endif // #ifdef _DEBUG 310 | 311 | result = S_OK; 312 | } while (false); 313 | 314 | return result; 315 | } 316 | 317 | HRESULT JSPod::InitializeDbgEng() 318 | { 319 | HRESULT result = E_FAIL; 320 | 321 | HRESULT hr = E_FAIL; 322 | 323 | do 324 | { 325 | 326 | hr = DebugCreate(__uuidof(IDebugClient), (PVOID *)&(this->m_debugClient)); 327 | if (!SUCCEEDED(hr)) 328 | { 329 | break; 330 | } 331 | 332 | hr = this->m_debugClient->QueryInterface(__uuidof(IDebugControl), (PVOID *)&(this->m_debugControl)); 333 | if (!SUCCEEDED(hr)) 334 | { 335 | break; 336 | } 337 | 338 | result = S_OK; 339 | } while (false); 340 | 341 | return result; 342 | } 343 | 344 | HRESULT JSPod::SetupBindings() 345 | { 346 | HRESULT result = E_FAIL; 347 | 348 | HRESULT hr = E_FAIL; 349 | 350 | JsErrorCode errorCode = JsErrorFatal; 351 | 352 | BindingDbgEng *dbgeng = nullptr; 353 | 354 | do 355 | { 356 | dbgeng = new BindingDbgEng(this->m_debugClient, this->m_debugControl); 357 | 358 | errorCode = dbgeng->Initialize(); 359 | if (JsNoError != errorCode) 360 | { 361 | break; 362 | } 363 | 364 | // for binding 365 | 366 | errorCode = this->m_binding->SetValue("", "dbgeng", dbgeng->GetHandle()); 367 | if (JsNoError != errorCode) 368 | { 369 | break; 370 | } 371 | 372 | // overwrite output 373 | errorCode = this->m_binding->SetRoutine("stdio", "output", dbgeng->ControlOutput, dbgeng); 374 | if (JsNoError != errorCode) 375 | { 376 | break; 377 | } 378 | 379 | 380 | 381 | result = S_OK; 382 | 383 | } while (false); 384 | 385 | return result; 386 | } 387 | 388 | HRESULT JSPod::BootstrapJSRT() 389 | { 390 | HRESULT result = E_FAIL; 391 | 392 | JsErrorCode errorCode = JsErrorFatal; 393 | 394 | uint32_t refs = 0; 395 | 396 | do 397 | { 398 | errorCode = JsExBootstrap(this->m_nativeRequire->GetHandle(), &(this->m_moduleRequire)); 399 | if (JsNoError != errorCode) 400 | { 401 | break; 402 | } 403 | 404 | errorCode = JsAddRef(this->m_moduleRequire, &refs); 405 | if (JsNoError != errorCode) 406 | { 407 | break; 408 | } 409 | 410 | result = S_OK; 411 | } while (false); 412 | 413 | return result; 414 | } 415 | 416 | JsErrorCode JSPod::RequireModule(_In_ const std::string &filename, _Out_ JsValueRef *exports) 417 | { 418 | return JsExRequireModule(this->m_moduleRequire, filename, exports); 419 | } 420 | 421 | JsErrorCode JSPod::PrintException() 422 | { 423 | return JsExDumpException(this->m_output); 424 | } 425 | 426 | void __cdecl JSPod::DebugPrintf(_In_ const char *format, ...) 427 | { 428 | va_list args; 429 | 430 | va_start(args, format); 431 | 432 | this->m_debugControl->ControlledOutputVaList(DEBUG_OUTCTL_ALL_CLIENTS, DEBUG_OUTPUT_NORMAL, format, args); 433 | 434 | va_end(args); 435 | } 436 | -------------------------------------------------------------------------------- /src/core/js_pod.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file jswd_pod.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_JS_POD_HEADER_FILE__ 10 | #define __MY_JS_POD_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include "precompile.h" 14 | 15 | #include "callbacks/standard_output_callbacks.h" 16 | 17 | #include "callbacks/standard_event_callbacks.h" 18 | 19 | class JSPod 20 | { 21 | public: 22 | JSPod(); 23 | 24 | ~JSPod(); 25 | 26 | public: 27 | HRESULT Initialize(); 28 | 29 | JsErrorCode RequireModule(_In_ const std::string &filename, _Out_ JsValueRef *exports); 30 | 31 | JsErrorCode PrintException(); 32 | 33 | void __cdecl DebugPrintf(_In_ const char *format, ...); 34 | 35 | protected: 36 | HRESULT InitializeJSRT(); 37 | 38 | HRESULT InitializeDbgEng(); 39 | 40 | HRESULT SetupBindings(); 41 | 42 | HRESULT BootstrapJSRT(); 43 | 44 | public: 45 | JsRuntimeHandle m_runtime; 46 | 47 | JsContextRef m_context; 48 | 49 | NativeBinding *m_binding; 50 | 51 | NativeBuiltin *m_builtin; 52 | 53 | NativeRequire *m_nativeRequire; 54 | 55 | JsValueRef m_moduleRequire; 56 | 57 | JsValueRef m_output; 58 | 59 | public: 60 | IDebugClient *m_debugClient; 61 | 62 | IDebugControl *m_debugControl; 63 | }; 64 | 65 | //////////////////////////////////////////////////// 66 | #endif //__MY_JS_POD_HEADER_FILE__ 67 | -------------------------------------------------------------------------------- /src/entrypoint.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file extension.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "version.h" 12 | 13 | #include "extension.h" 14 | 15 | #include "entrypoint.h" 16 | 17 | //////////////////////////////////////////////////////////////////////////////////////////////// 18 | 19 | #ifdef _WIN64 20 | EXT_API_VERSION APIVersion = {MY_VERSION_MAJOR, MY_VERSION_MINOR, EXT_API_VERSION_NUMBER64, 0}; 21 | #else 22 | EXT_API_VERSION APIVersion = {MY_VERSION_MAJOR, MY_VERSION_MINOR, EXT_API_VERSION_NUMBER32, 0}; 23 | #endif 24 | 25 | EXTERN_C LPEXT_API_VERSION __stdcall ExtensionApiVersion(void) 26 | { 27 | return &APIVersion; 28 | } 29 | 30 | EXTERN_C HRESULT __stdcall DebugExtensionInitialize(__out ULONG *pVersion, __out ULONG *pFlags) 31 | { 32 | HRESULT result = E_FAIL; 33 | 34 | HRESULT hr = E_FAIL; 35 | 36 | Extension *extension = Extension::GetInstance(); 37 | 38 | do 39 | { 40 | hr = extension->Initialize(); 41 | if (!SUCCEEDED(hr)) 42 | { 43 | result = hr; 44 | break; 45 | } 46 | 47 | result = S_OK; 48 | 49 | } while (false); 50 | 51 | return result; 52 | } 53 | 54 | EXTERN_C void __stdcall DebugExtensionUninitialize(void) 55 | { 56 | Extension *extension = Extension::GetInstance(); 57 | 58 | delete extension; 59 | } 60 | 61 | EXTERN_C HRESULT __stdcall KnownStructOutput(__in ULONG flags, __in ULONG64 address, __in PSTR structName, 62 | __out PSTR buffer, __inout PULONG pbufferSize) 63 | { 64 | return S_OK; 65 | } 66 | -------------------------------------------------------------------------------- /src/entrypoint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file extension.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_ENTRYPOINT_HEADER_FILE__ 10 | #define __MY_ENTRYPOINT_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include 14 | 15 | EXTERN_C HRESULT __stdcall DebugExtensionInitialize(__out ULONG *pVersion, __out ULONG *pFlags); 16 | 17 | EXTERN_C void __stdcall DebugExtensionUninitialize(void); 18 | 19 | //////////////////////////////////////////////////// 20 | #endif //__MY_ENTRYPOINT_HEADER_FILE__ 21 | -------------------------------------------------------------------------------- /src/exports.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DebugExtensionInitialize @ 1 3 | DebugExtensionUninitialize @ 2 4 | ExtensionApiVersion @ 3 5 | KnownStructOutput @ 4 6 | 7 | jshelp 8 | jscall 9 | jsrun 10 | jsload 11 | jsunload 12 | jsclear 13 | jslist 14 | 15 | help = jshelp 16 | call = jscall 17 | js = jsrun 18 | run = jsrun 19 | load = jsload 20 | unload = jsunload 21 | list = jslist 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/extension.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file solar.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include "precompile.h" 10 | 11 | #include "extension.h" 12 | 13 | #include "version.h" 14 | 15 | Extension *extensionInstance = nullptr; 16 | 17 | Extension::Extension() 18 | { 19 | this->m_pod = new JSPod(); 20 | } 21 | 22 | Extension::~Extension() 23 | { 24 | if (nullptr != this->m_pod) 25 | { 26 | delete this->m_pod; 27 | 28 | this->m_pod = nullptr; 29 | } 30 | } 31 | 32 | Extension *Extension::GetInstance() 33 | { 34 | if (nullptr == extensionInstance) 35 | { 36 | extensionInstance = new Extension(); 37 | } 38 | 39 | return extensionInstance; 40 | } 41 | 42 | HRESULT Extension::Initialize() 43 | { 44 | HRESULT result = E_FAIL; 45 | 46 | HRESULT hr = E_FAIL; 47 | 48 | do 49 | { 50 | hr = this->m_pod->Initialize(); 51 | if (!SUCCEEDED(hr)) 52 | { 53 | result = hr; 54 | break; 55 | } 56 | 57 | this->m_pod->DebugPrintf(MY_BANNER); 58 | 59 | this->m_pod->DebugPrintf("use !js.help to get the usage , have a nice day.\n"); 60 | 61 | result = S_OK; 62 | } while (false); 63 | 64 | return result; 65 | } 66 | 67 | void Extension::printUsage() 68 | { 69 | do 70 | { 71 | 72 | this->m_pod->DebugPrintf(MY_BANNER); 73 | 74 | this->m_pod->DebugPrintf("Version: %d.%d.%d.%d , build from %s.%s , compile at %s %s\n", 75 | MY_VERSION_MAJOR, 76 | MY_VERSION_MINOR, 77 | MY_VERSION_PART_3, 78 | MY_VERSION_PART_4, 79 | GIT_BRANCH, 80 | GIT_COMMIT_HASH, 81 | __DATE__, __TIME__); 82 | 83 | this->m_pod->DebugPrintf("You can get help from https://github.com/tinysec/jswd\n"); 84 | 85 | this->m_pod->DebugPrintf("Usage: !js.[command] [args]...\n"); 86 | 87 | this->m_pod->DebugPrintf( 88 | "+-------------+----------------------------+---------------------------------------+\n"); 89 | 90 | this->m_pod->DebugPrintf( 91 | "| command | usage | decription |\n"); 92 | 93 | this->m_pod->DebugPrintf( 94 | "+-------------+----------------------------+---------------------------------------+\n"); 95 | 96 | this->m_pod->DebugPrintf( 97 | "| !js | !js script.js | same as !jsrun |\n"); 98 | 99 | this->m_pod->DebugPrintf( 100 | "| !jshelp | !jshelp | print help |\n"); 101 | 102 | this->m_pod->DebugPrintf( 103 | "| !jscall | !jscall script.js foobar | call a already loaded file's method |\n"); 104 | 105 | this->m_pod->DebugPrintf( 106 | "| !jsrun | !jsrun script.js | run a script file and call main |\n"); 107 | 108 | this->m_pod->DebugPrintf( 109 | "| !jslist | !jslist | list all loaded script files |\n"); 110 | 111 | this->m_pod->DebugPrintf( 112 | "| !jsclear | !jsclear | unload all loaded script files |\n"); 113 | 114 | this->m_pod->DebugPrintf( 115 | "| !jsload | !jsload script.js | load a script file |\n"); 116 | 117 | this->m_pod->DebugPrintf( 118 | "| !jsunload | !jsunload script.js | unload a already loaded file |\n"); 119 | 120 | this->m_pod->DebugPrintf( 121 | "| !js.help | !js.help | same as !jshelp |\n"); 122 | 123 | this->m_pod->DebugPrintf( 124 | "| !js.js | !js.js script.js | same as !jsrun |\n"); 125 | 126 | this->m_pod->DebugPrintf( 127 | "| !js.call | !js.call script.js | same as !jscall |\n"); 128 | 129 | this->m_pod->DebugPrintf( 130 | "| !js.run | !js.run script.js | same as !jsrun |\n"); 131 | 132 | this->m_pod->DebugPrintf( 133 | "| !js.clear | !js.clear | same as !jsclear |\n"); 134 | 135 | this->m_pod->DebugPrintf( 136 | "| !js.list | !js.list | same as !jslist |\n"); 137 | 138 | this->m_pod->DebugPrintf( 139 | "| !js.load | !js.load script.js | same as !jsload |\n"); 140 | 141 | this->m_pod->DebugPrintf( 142 | "| !js.unload | !js.unload script.js | same as !jsunload |\n"); 143 | 144 | this->m_pod->DebugPrintf( 145 | "+-------------+----------------------------+---------------------------------------+\n"); 146 | 147 | } while (false); 148 | } 149 | 150 | 151 | JsValueRef Extension::FindScript(const std::string& name) 152 | { 153 | std::map::iterator it; 154 | 155 | it = this->m_scripts.find( name ); 156 | if (this->m_scripts.end() == it ) 157 | { 158 | return nullptr; 159 | } 160 | 161 | return it->second; 162 | } 163 | 164 | bool Extension::AddScript(const std::string& name , JsValueRef exports) 165 | { 166 | std::map::iterator it; 167 | 168 | it = this->m_scripts.find( name ); 169 | if (this->m_scripts.end() != it ) 170 | { 171 | return false; 172 | } 173 | 174 | JsAddRef(exports , nullptr); 175 | 176 | this->m_scripts[name] = exports; 177 | 178 | return true; 179 | } 180 | 181 | JsValueRef Extension::RemoveScript(const std::string& name) 182 | { 183 | std::map::iterator it; 184 | 185 | JsValueRef exports = nullptr; 186 | 187 | it = this->m_scripts.find( name ); 188 | if (this->m_scripts.end() == it ) 189 | { 190 | return nullptr; 191 | } 192 | 193 | exports = it->second; 194 | 195 | this->m_scripts.erase(it); 196 | 197 | return exports; 198 | } 199 | 200 | -------------------------------------------------------------------------------- /src/extension.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file solar.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_EXTENSION_HEADER_FILE__ 10 | #define __MY_EXTENSION_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include "src/precompile.h" 14 | 15 | #include "core/js_pod.h" 16 | 17 | class Extension 18 | { 19 | public: 20 | Extension(); 21 | 22 | ~Extension(); 23 | 24 | public: 25 | static Extension *GetInstance(); 26 | 27 | public: 28 | 29 | HRESULT Initialize(); 30 | 31 | void printUsage(); 32 | 33 | 34 | public: 35 | 36 | JsValueRef FindScript(const std::string& name); 37 | 38 | bool AddScript(const std::string& name , JsValueRef exports); 39 | 40 | JsValueRef RemoveScript(const std::string& name); 41 | 42 | 43 | public: 44 | 45 | JSPod *m_pod; 46 | 47 | public: 48 | std::map m_scripts; 49 | }; 50 | 51 | //////////////////////////////////////////////////// 52 | #endif //__MY_EXTENSION_HEADER_FILE__ 53 | -------------------------------------------------------------------------------- /src/git_version.h.in: -------------------------------------------------------------------------------- 1 | /** 2 | * @file git_version.h.in.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | * 2023-06-07 init 7 | */ 8 | 9 | #ifndef __MY_GIT_VERSION_H_IN_HEADER_FILE__ 10 | #define __MY_GIT_VERSION_H_IN_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | #ifdef __cplusplus 13 | extern "C" 14 | { 15 | #endif 16 | //////////////////////////////////////////////////// 17 | 18 | #define GIT_BRANCH "${GIT_BRANCH}" 19 | 20 | #define GIT_COMMIT_HASH "${GIT_COMMIT_HASH}" 21 | 22 | //////////////////////////////////////////////////// 23 | #ifdef __cplusplus 24 | } // extern "C" 25 | #endif 26 | //////////////////////////////////////////////////// 27 | #endif //__MY_GIT_VERSION_H_IN_HEADER_FILE__ 28 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file main.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | * 22-12-21 init 7 | */ 8 | 9 | #ifndef BUILD_TESTS 10 | //////////////////////////////////////////////////////////////////////////////////////// 11 | 12 | #include 13 | 14 | #ifdef BUILD_LIBRARY 15 | 16 | BOOL __stdcall DllMain(__in HMODULE module, __in DWORD reason, LPVOID lparam) 17 | { 18 | UNREFERENCED_PARAMETER(module); 19 | UNREFERENCED_PARAMETER(reason); 20 | UNREFERENCED_PARAMETER(lparam); 21 | 22 | switch (reason) 23 | { 24 | case DLL_PROCESS_ATTACH: { 25 | 26 | break; 27 | } 28 | case DLL_PROCESS_DETACH: { 29 | 30 | break; 31 | } 32 | default: { 33 | break; 34 | } 35 | } 36 | 37 | return TRUE; 38 | } 39 | 40 | #else 41 | 42 | int main(int argc, char **argv) 43 | { 44 | 45 | return 0; 46 | } 47 | 48 | #endif // #ifdef BUILD_LIBRARY 49 | 50 | //////////////////////////////////////////////////////////////////////////////////////// 51 | #endif // #ifndef BUILD_TESTS 52 | -------------------------------------------------------------------------------- /src/precompile.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file precompile.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_PRECOMPILE_HEADER_FILE__ 10 | #define __MY_PRECOMPILE_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | 21 | //////////////////////////////////////////////////// 22 | #endif //__MY_PRECOMPILE_HEADER_FILE__ 23 | -------------------------------------------------------------------------------- /src/script/jswd.js: -------------------------------------------------------------------------------- 1 | const _ = require('underscore'); 2 | 3 | const dbgeng = require('dbgeng'); 4 | 5 | let moduleExports = _.extend( 6 | require('jswd/module'), 7 | require('jswd/processor'), 8 | require('jswd/register'), 9 | require('jswd/segment'), 10 | require('jswd/symbol'), 11 | require('jswd/virtual'), 12 | ); 13 | 14 | moduleExports.physical = require('jswd/physical'); 15 | 16 | 17 | // forward 18 | 19 | moduleExports.writeDumpFile = dbgeng.writeDumpFile; 20 | 21 | moduleExports.isKernelDebuggerEnabled = dbgeng.isKernelDebuggerEnabled; 22 | 23 | moduleExports.assemble = dbgeng.assemble; 24 | 25 | moduleExports.callExtension = dbgeng.callExtension; 26 | 27 | moduleExports.disassemble = dbgeng.disassemble; 28 | 29 | moduleExports.execute = dbgeng.execute; 30 | 31 | moduleExports.getPageSize = dbgeng.getPageSize; 32 | 33 | moduleExports.isPointer64Bit = dbgeng.isPointer64Bit; 34 | 35 | moduleExports.readMsr = dbgeng.readMsr; 36 | 37 | moduleExports.writeMsr = dbgeng.writeMsr; 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | // exports 46 | module.exports = moduleExports; 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/script/jswd/module.js: -------------------------------------------------------------------------------- 1 | 2 | const assert = require("assert"); 3 | 4 | const typing = require("typing"); 5 | 6 | const dbgeng = require("dbgeng"); 7 | 8 | const fmt = require('fmt'); 9 | 10 | const int = require('integer'); 11 | 12 | const Uint64 = int.Uint64; 13 | 14 | class Module 15 | { 16 | /*** 17 | * 18 | * @param {Uint64} imageBase 19 | */ 20 | constructor(imageBase) { 21 | 22 | assert( Uint64.isUint64(imageBase) ); 23 | 24 | this.imageBase = imageBase; 25 | 26 | this.imageSize = 0; 27 | 28 | this.imageName = ''; 29 | 30 | this.moduleName = ''; 31 | 32 | this.loadedImageName = ''; 33 | 34 | this.unloaded = false; 35 | 36 | this.timeDateStamp = 0; 37 | 38 | this.checksum = 0; 39 | 40 | this.flags = 0; 41 | 42 | this.symbolType = 0; 43 | } 44 | } 45 | exports.Module = Module; 46 | 47 | 48 | 49 | function queryModule(index) 50 | { 51 | let base = dbgeng.getModuleByIndex(index); 52 | 53 | let item = new Module(base); 54 | 55 | let names = dbgeng.getModuleNames( index , base); 56 | 57 | item.imageName = names.imageName; 58 | 59 | item.moduleName = names.moduleName; 60 | 61 | item.loadedImageName = names.loadedImageName; 62 | 63 | // module size 64 | let parameters = dbgeng.getModuleParameters(index) 65 | 66 | item.imageSize = parameters.imageSize; 67 | 68 | item.timeDateStamp = parameters.timeDateStamp; 69 | 70 | item.checksum = parameters.checksum; 71 | 72 | item.flags = parameters.flags; 73 | 74 | item.symbolType = parameters.symbolType; 75 | 76 | return item; 77 | } 78 | 79 | 80 | /** 81 | * enum all modules 82 | * @returns {*[]} 83 | */ 84 | function enumModule() 85 | { 86 | let info = dbgeng.getNumberModules(); 87 | 88 | let item = null; 89 | 90 | let items = []; 91 | 92 | let index = 0; 93 | 94 | for ( index = 0; index < info.loaded; index++ ) 95 | { 96 | item = queryModule(index); 97 | 98 | item.unloaded = false; 99 | 100 | items.push( item ); 101 | } 102 | 103 | for ( index = info.loaded; index < info.loaded + info.unloaded; index++ ) 104 | { 105 | item = queryModule(index); 106 | 107 | item.unloaded = true; 108 | 109 | items.push( item ); 110 | } 111 | 112 | return items; 113 | } 114 | exports.enumModule = enumModule; 115 | 116 | function findModule(name , start = 0) 117 | { 118 | let info = dbgeng.getModuleByName(name , start); 119 | 120 | return queryModule(info.index); 121 | } 122 | exports.findModule = findModule; 123 | 124 | function getModuleBase(name , start = 0) 125 | { 126 | let item = findModule(name , start); 127 | 128 | return item.imageBase; 129 | } 130 | exports.getModuleBase = getModuleBase; -------------------------------------------------------------------------------- /src/script/jswd/physical.js: -------------------------------------------------------------------------------- 1 | const _ = require('underscore'); 2 | 3 | const typing = require("typing"); 4 | 5 | const dbgeng = require("dbgeng"); 6 | 7 | const readerExports = require('jswd/reader'); 8 | 9 | const writerExports = require('jswd/writer'); 10 | 11 | 12 | class Reader 13 | { 14 | constructor() 15 | { 16 | 17 | } 18 | 19 | read(address , buffer) 20 | { 21 | return dbgeng.readPhysical(address , buffer); 22 | } 23 | } 24 | 25 | class Writer 26 | { 27 | constructor() 28 | { 29 | 30 | } 31 | 32 | write(address , buffer) 33 | { 34 | return dbgeng.writePhysical(address , buffer); 35 | } 36 | } 37 | 38 | 39 | let name = ''; 40 | 41 | let routine = null; 42 | 43 | let reader = new Reader(); 44 | 45 | let writer = new Writer(); 46 | 47 | for ( name in readerExports) 48 | { 49 | routine = readerExports[name]; 50 | 51 | if ( typing.isFunction(routine) ) 52 | { 53 | exports[name] = routine.bind(this , reader); 54 | } 55 | } 56 | 57 | 58 | // for writer 59 | for ( name in writerExports ) 60 | { 61 | routine = writerExports[name]; 62 | 63 | if ( typing.isFunction(routine) ) 64 | { 65 | exports[name] = routine.bind(this , writer); 66 | } 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/script/jswd/processor.js: -------------------------------------------------------------------------------- 1 | const dbgeng = require("dbgeng"); 2 | 3 | const reg = require('jswd/register'); 4 | 5 | class Processor 6 | { 7 | constructor(id) 8 | { 9 | this.id = id; 10 | 11 | this.registers = []; 12 | } 13 | } 14 | 15 | 16 | function enumProcessor() 17 | { 18 | let count = dbgeng.getNumberProcessors(); 19 | 20 | let i = 0; 21 | 22 | let processor = null; 23 | 24 | let oldTid = dbgeng.getCurrentThreadId(); 25 | 26 | let tid = 0; 27 | 28 | let processors = []; 29 | 30 | for ( i = 0; i < count; i++ ) 31 | { 32 | processor = new Processor(i); 33 | 34 | tid = dbgeng.getThreadIdByProcessor(i); 35 | 36 | dbgeng.setCurrentThreadId(tid); 37 | 38 | processor.registers = reg.enumRegister(); 39 | 40 | processors.push( processor ); 41 | } 42 | 43 | dbgeng.setCurrentThreadId(oldTid); 44 | 45 | return processors; 46 | } 47 | exports.enumProcessor = enumProcessor; 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/script/jswd/reader.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | 3 | const typing = require("typing"); 4 | 5 | const fmt = require('fmt'); 6 | 7 | const maxStringLength = 65536; 8 | 9 | 10 | function readFloat32BE(reader , address) 11 | { 12 | let buffer = new ArrayBuffer(4); 13 | 14 | let view = new DataView(buffer); 15 | 16 | let readed = 0; 17 | 18 | readed = reader.read(address , buffer); 19 | if ( buffer.byteLength !== readed ) 20 | { 21 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 22 | } 23 | 24 | return view.getFloat32(0 , false); 25 | } 26 | exports.readFloat32BE = readFloat32BE; 27 | 28 | function readFloat32LE(reader ,address) 29 | { 30 | let buffer = new ArrayBuffer(4); 31 | 32 | let view = new DataView(buffer); 33 | 34 | let readed = 0; 35 | 36 | readed = reader.read(address , buffer); 37 | if ( buffer.byteLength !== readed ) 38 | { 39 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 40 | } 41 | 42 | return view.getFloat32(0 , true); 43 | } 44 | exports.readFloat32LE = readFloat32LE; 45 | 46 | 47 | 48 | function readFloat64BE(reader ,address) 49 | { 50 | let buffer = new ArrayBuffer(8); 51 | 52 | let view = new DataView(buffer); 53 | 54 | let readed = 0; 55 | 56 | readed = reader.read(address , buffer); 57 | if ( buffer.byteLength !== readed ) 58 | { 59 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 60 | } 61 | 62 | return view.getFloat64(0 , true); 63 | } 64 | exports.readFloat64BE = readFloat64BE; 65 | 66 | 67 | function readFloat64LE(reader ,address) 68 | { 69 | let buffer = new ArrayBuffer(8); 70 | 71 | let view = new DataView(buffer); 72 | 73 | let readed = 0; 74 | 75 | readed = reader.read(address , buffer); 76 | if ( buffer.byteLength !== readed ) 77 | { 78 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 79 | } 80 | 81 | return view.getFloat64(0 , true); 82 | } 83 | exports.readFloat64LE = readFloat64LE; 84 | 85 | //--------------------------------for signed---------------------------------------------------------------- 86 | 87 | 88 | function readInt8(reader ,address) 89 | { 90 | let buffer = new ArrayBuffer(1); 91 | 92 | let view = new DataView(buffer); 93 | 94 | let readed = 0; 95 | 96 | readed = reader.read(address , buffer); 97 | if ( buffer.byteLength !== readed ) 98 | { 99 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 100 | } 101 | 102 | return view.getInt8(0); 103 | } 104 | exports.readInt8 = readInt8; 105 | 106 | function readInt16BE(reader ,address) 107 | { 108 | let buffer = new ArrayBuffer(2); 109 | 110 | let view = new DataView(buffer); 111 | 112 | let readed = 0; 113 | 114 | readed = reader.read(address , buffer); 115 | if ( buffer.byteLength !== readed ) 116 | { 117 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 118 | } 119 | 120 | return view.getInt16(0 , false); 121 | } 122 | exports.readInt16BE = readInt16BE; 123 | 124 | function readInt16LE(reader ,address) 125 | { 126 | let buffer = new ArrayBuffer(2); 127 | 128 | let view = new DataView(buffer); 129 | 130 | let readed = 0; 131 | 132 | readed = reader.read(address , buffer); 133 | if ( buffer.byteLength !== readed ) 134 | { 135 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 136 | } 137 | 138 | return view.getInt16(0 , true); 139 | } 140 | exports.readInt16LE = readInt16LE; 141 | 142 | 143 | 144 | function readInt32BE(reader ,address) 145 | { 146 | let buffer = new ArrayBuffer(4); 147 | 148 | let view = new DataView(buffer); 149 | 150 | let readed = 0; 151 | 152 | readed = reader.read(address , buffer); 153 | if ( buffer.byteLength !== readed ) 154 | { 155 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 156 | } 157 | 158 | return view.getInt32(0 , false); 159 | } 160 | exports.readInt32BE = readInt32BE; 161 | 162 | 163 | function readInt32LE(reader ,address) 164 | { 165 | let buffer = new ArrayBuffer(4); 166 | 167 | let view = new DataView(buffer); 168 | 169 | let readed = 0; 170 | 171 | readed = reader.read(address , buffer); 172 | if ( buffer.byteLength !== readed ) 173 | { 174 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 175 | } 176 | 177 | return view.getInt32(0 , true); 178 | } 179 | exports.readInt32LE = readInt32LE; 180 | 181 | 182 | 183 | function readInt64BE(reader ,address) 184 | { 185 | let buffer = new ArrayBuffer(8); 186 | 187 | let view = new DataView(buffer); 188 | 189 | let readed = 0; 190 | 191 | let value = null; 192 | 193 | readed = reader.read(address , buffer); 194 | if ( buffer.byteLength !== readed ) 195 | { 196 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 197 | } 198 | 199 | value = new Int64(0); 200 | 201 | value.low = view.getInt32(4 , false); 202 | 203 | value.high = view.getInt32(0, false); 204 | 205 | return value; 206 | } 207 | exports.readInt64BE = readInt64BE; 208 | 209 | function readInt64LE(reader ,address) 210 | { 211 | let buffer = new ArrayBuffer(8); 212 | 213 | let view = new DataView(buffer); 214 | 215 | let readed = 0; 216 | 217 | let value = null; 218 | 219 | readed = reader.read(address , buffer); 220 | if ( buffer.byteLength !== readed ) 221 | { 222 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 223 | } 224 | 225 | value = new Int64(0); 226 | 227 | value.low = view.getInt32(0 , true); 228 | 229 | value.high = view.getInt32(4 , true); 230 | 231 | return value; 232 | } 233 | exports.readInt64LE = readInt64LE; 234 | 235 | 236 | 237 | //--------------------------------for unsigned---------------------------------------------------------------- 238 | 239 | 240 | 241 | function readUint8(reader ,address) 242 | { 243 | let buffer = new ArrayBuffer(1); 244 | 245 | let view = new DataView(buffer); 246 | 247 | let readed = 0; 248 | 249 | readed = reader.read(address , buffer); 250 | if ( buffer.byteLength !== readed ) 251 | { 252 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 253 | } 254 | 255 | return view.getUint8(0); 256 | } 257 | exports.readUint8 = readUint8; 258 | 259 | function readUint16BE(reader ,address) 260 | { 261 | let buffer = new ArrayBuffer(2); 262 | 263 | let view = new DataView(buffer); 264 | 265 | let readed = 0; 266 | 267 | readed = reader.read(address , buffer); 268 | if ( buffer.byteLength !== readed ) 269 | { 270 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 271 | } 272 | 273 | return view.getUint16(0 , false); 274 | } 275 | exports.readUint16BE = readUint16BE; 276 | 277 | function readUint16LE(reader ,address) 278 | { 279 | let buffer = new ArrayBuffer(2); 280 | 281 | let view = new DataView(buffer); 282 | 283 | let readed = 0; 284 | 285 | readed = reader.read(address , buffer); 286 | if ( buffer.byteLength !== readed ) 287 | { 288 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 289 | } 290 | 291 | return view.getUint16(0 , true); 292 | } 293 | exports.readUint16LE = readUint16LE; 294 | 295 | 296 | 297 | function readUint32BE(reader ,address) 298 | { 299 | let buffer = new ArrayBuffer(4); 300 | 301 | let view = new DataView(buffer); 302 | 303 | let readed = 0; 304 | 305 | readed = reader.read(address , buffer); 306 | if ( buffer.byteLength !== readed ) 307 | { 308 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 309 | } 310 | 311 | return view.getUint32(0 , false); 312 | } 313 | exports.readUint32BE = readUint32BE; 314 | 315 | 316 | function readUint32LE(reader ,address) 317 | { 318 | let buffer = new ArrayBuffer(4); 319 | 320 | let view = new DataView(buffer); 321 | 322 | let readed = 0; 323 | 324 | readed = reader.read(address , buffer); 325 | if ( buffer.byteLength !== readed ) 326 | { 327 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 328 | } 329 | 330 | return view.getUint32(0 , true); 331 | } 332 | exports.readUint32LE = readUint32LE; 333 | 334 | 335 | 336 | function readUint64BE(reader ,address) 337 | { 338 | let buffer = new ArrayBuffer(8); 339 | 340 | let view = new DataView(buffer); 341 | 342 | let readed = 0; 343 | 344 | let value = null; 345 | 346 | readed = reader.read(address , buffer); 347 | if ( buffer.byteLength !== readed ) 348 | { 349 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 350 | } 351 | 352 | value = new Uint64(0); 353 | 354 | value.low = view.getUint32(4 , false); 355 | 356 | value.high = view.getUint32(0 , false); 357 | 358 | return value; 359 | } 360 | exports.readUint64BE = readUint64BE; 361 | 362 | function readUint64LE(reader ,address) 363 | { 364 | let buffer = new ArrayBuffer(8); 365 | 366 | let view = new DataView(buffer); 367 | 368 | let readed = 0; 369 | 370 | let value = null; 371 | 372 | readed = reader.read(address , buffer); 373 | if ( buffer.byteLength !== readed ) 374 | { 375 | throw new Error(fmt.sprintf('read %s fail , readed %d bytes' , address , readed) ) 376 | } 377 | 378 | value = new Uint64(0); 379 | 380 | value.low = view.getUint32(0 , true); 381 | 382 | value.high = view.getUint32(4 , true); 383 | 384 | return value; 385 | } 386 | exports.readUint64LE = readUint64LE; 387 | 388 | 389 | //--------------------------------for string---------------------------------------------------------------- 390 | 391 | 392 | function readString(reader ,address , length) 393 | { 394 | let bufferSize = maxStringLength; 395 | 396 | let buffer = null; 397 | 398 | let view = null; 399 | 400 | let i = 0; 401 | 402 | let textLength = 0; 403 | 404 | let bytesReaded = 0; 405 | 406 | let decoder = null; 407 | 408 | if ( arguments.length >= 2 ) 409 | { 410 | assert( typing.isNumber(length) ); 411 | 412 | if ( length < 0) 413 | { 414 | bufferSize = maxStringLength; 415 | } 416 | else 417 | { 418 | bufferSize = length; 419 | } 420 | } 421 | 422 | buffer = new ArrayBuffer(bufferSize); 423 | 424 | view = new DataView(view); 425 | 426 | bytesReaded = reader.read(address , buffer); 427 | 428 | if ( 0 === bytesReaded ) 429 | { 430 | return ''; 431 | } 432 | 433 | for ( i = 0; i < bytesReaded; i++ ) 434 | { 435 | if ( '\0'.charCodeAt(0) === view.getUint8(i) ) 436 | { 437 | break; 438 | } 439 | 440 | textLength++; 441 | } 442 | 443 | decoder = new TextDecoder('utf-8'); 444 | 445 | return decoder.decode( buffer.slice(0 , textLength) ); 446 | } 447 | exports.readString = readString; 448 | 449 | function readWideString(reader ,address , length) 450 | { 451 | let bufferSize = maxStringLength; 452 | 453 | let buffer = null; 454 | 455 | let view = null; 456 | 457 | let i = 0; 458 | 459 | let textLength = 0; 460 | 461 | let bytesReaded = 0; 462 | 463 | let decoder = null; 464 | 465 | if ( arguments.length >= 2 ) 466 | { 467 | assert( typing.isNumber(length) ); 468 | 469 | if ( length < 0) 470 | { 471 | bufferSize = maxStringLength; 472 | } 473 | else 474 | { 475 | bufferSize = length; 476 | } 477 | } 478 | 479 | buffer = new ArrayBuffer(bufferSize); 480 | 481 | view = new DataView(view); 482 | 483 | bytesReaded = reader.read(address , buffer); 484 | 485 | if ( 0 === bytesReaded ) 486 | { 487 | return ''; 488 | } 489 | 490 | for ( i = 0; i < bytesReaded; i += 2 ) 491 | { 492 | if ( '\0'.charCodeAt(0) === view.getUint8(i) && '\0'.charCodeAt(0) === view.getUint8(i+i) ) 493 | { 494 | break; 495 | } 496 | 497 | textLength += 2; 498 | } 499 | 500 | decoder = new TextDecoder('utf-16'); 501 | 502 | return decoder.decode( buffer.slice(0 , textLength) ); 503 | } 504 | exports.readWideString = readWideString; 505 | 506 | 507 | -------------------------------------------------------------------------------- /src/script/jswd/register.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | 3 | const typing = require("typing"); 4 | 5 | const dbgeng = require("dbgeng"); 6 | 7 | const fmt = require('fmt'); 8 | 9 | class Register 10 | { 11 | constructor(index) { 12 | 13 | //this.index = index; 14 | 15 | Object.defineProperty(this, 'index', { 16 | value: index, 17 | writable: false, 18 | enumerable: false, 19 | configurable: true 20 | }); 21 | 22 | this.name = ''; 23 | 24 | this.bits = 0; 25 | 26 | this.type = 0; 27 | 28 | this.value = 0; 29 | 30 | this.child = false; 31 | } 32 | 33 | getValue() 34 | { 35 | return dbgeng.getRegisterValue(this.index); 36 | } 37 | 38 | setValue(newValue) 39 | { 40 | let argValue = 0; 41 | 42 | if ( this.bits <= 8 ) 43 | { 44 | if ( typing.isNumber(newValue) ) 45 | { 46 | argValue = newValue & 0xff; 47 | } 48 | else if ( Uint64.isUint64(newValue) ) 49 | { 50 | argValue = newValue.and( 0xff).toNumber(); 51 | } 52 | else if ( typing.isUint8Array(newValue) ) 53 | { 54 | argValue = newValue; 55 | } 56 | else 57 | { 58 | assert( typing.isString(newValue) ); 59 | 60 | argValue = new Uint64(newValue).and(0xff).toNumber(); 61 | } 62 | } 63 | else if ( this.bits <= 16 ) 64 | { 65 | if ( typing.isNumber(newValue) ) 66 | { 67 | argValue = newValue & 0xffff; 68 | } 69 | else if ( Uint64.isUint64(newValue) ) 70 | { 71 | argValue = newValue.and( 0xffff).toNumber(); 72 | } 73 | else if ( typing.isUint8Array(newValue) ) 74 | { 75 | argValue = newValue; 76 | } 77 | else 78 | { 79 | assert( typing.isString(newValue) ); 80 | 81 | argValue = new Uint64(newValue).and(0xffff).toNumber(); 82 | } 83 | } 84 | else if ( this.bits <= 32 ) 85 | { 86 | if ( typing.isNumber(newValue) ) 87 | { 88 | argValue = newValue & 0xffffffff; 89 | } 90 | else if ( Uint64.isUint64(newValue) ) 91 | { 92 | argValue = newValue.and( 0xffffffff).toNumber(); 93 | } 94 | else if ( typing.isUint8Array(newValue) ) 95 | { 96 | argValue = newValue; 97 | } 98 | else 99 | { 100 | assert( typing.isString(newValue) ); 101 | 102 | argValue = new Uint64(newValue).and(0xffffffff).toNumber(); 103 | } 104 | } 105 | else if ( this.bits <= 64 ) 106 | { 107 | if ( typing.isNumber(newValue) ) 108 | { 109 | argValue = newValue; 110 | } 111 | else if ( Uint64.isUint64(newValue) ) 112 | { 113 | argValue = newValue; 114 | } 115 | else if ( typing.isUint8Array(newValue) ) 116 | { 117 | argValue = newValue; 118 | } 119 | else 120 | { 121 | assert( typing.isString(newValue) ); 122 | 123 | argValue = new Uint64(newValue); 124 | } 125 | } 126 | else if ( this.bits <= 128 ) 127 | { 128 | if ( typing.isNumber(newValue) ) 129 | { 130 | argValue = newValue; 131 | } 132 | else if ( Uint64.isUint64(newValue) ) 133 | { 134 | argValue = newValue; 135 | } 136 | else if ( typing.isUint8Array(newValue) ) 137 | { 138 | argValue = newValue; 139 | } 140 | else 141 | { 142 | assert( typing.isString(newValue) ); 143 | 144 | argValue = new Uint64(newValue); 145 | } 146 | } 147 | 148 | this.value = argValue; 149 | 150 | return dbgeng.setRegisterValue(this.index , this.type , argValue ); 151 | } 152 | } 153 | exports.Register = Register; 154 | 155 | function findRegister(nameOrIndex) 156 | { 157 | let index = 0; 158 | 159 | let desc = null; 160 | 161 | let item = null; 162 | 163 | let child = false; 164 | 165 | if ( typing.isString(nameOrIndex) ) 166 | { 167 | index = dbgeng.getRegisterIndex(nameOrIndex); 168 | } 169 | else 170 | { 171 | assert( typing.isNumber(nameOrIndex) ); 172 | 173 | index = nameOrIndex; 174 | } 175 | 176 | desc = dbgeng.getRegisterDescription(index); 177 | 178 | item = new Register(index); 179 | 180 | item.name = desc.name; 181 | 182 | item.type = desc.type; 183 | 184 | item.value = item.getValue(); 185 | 186 | child = ( 0 !== ( desc.flags & dbgeng.DEBUG_REGISTER_SUB_REGISTER) ); 187 | 188 | if ( child ) 189 | { 190 | item.bits = desc.subregLength; 191 | } 192 | 193 | item.child = child; 194 | 195 | if ( dbgeng.DEBUG_VALUE_INT8 === desc.type ) 196 | { 197 | if ( !child ) 198 | { 199 | item.bits = 8; 200 | } 201 | } 202 | else if ( dbgeng.DEBUG_VALUE_INT16 === desc.type ) 203 | { 204 | if ( !child ) 205 | { 206 | item.bits = 16; 207 | } 208 | } 209 | else if ( dbgeng.DEBUG_VALUE_INT32 === desc.type ) 210 | { 211 | if ( !child ) 212 | { 213 | item.bits = 32; 214 | } 215 | } 216 | else if ( dbgeng.DEBUG_VALUE_INT64 === desc.type ) 217 | { 218 | if ( !child ) 219 | { 220 | item.bits = 64; 221 | } 222 | } 223 | else if ( dbgeng.DEBUG_VALUE_FLOAT32 === desc.type ) 224 | { 225 | if ( !child ) 226 | { 227 | item.bits = 32; 228 | } 229 | } 230 | else if ( dbgeng.DEBUG_VALUE_FLOAT64 === desc.type ) 231 | { 232 | if ( !child ) 233 | { 234 | item.bits = 64; 235 | } 236 | } 237 | else if ( dbgeng.DEBUG_VALUE_FLOAT80 === desc.type ) 238 | { 239 | if ( !child ) 240 | { 241 | item.bits = 80; 242 | } 243 | } 244 | else if ( dbgeng.DEBUG_VALUE_FLOAT82 === desc.type ) 245 | { 246 | if ( !child ) 247 | { 248 | item.bits = 82; 249 | } 250 | } 251 | else if ( dbgeng.DEBUG_VALUE_FLOAT128 === desc.type ) 252 | { 253 | if ( !child ) 254 | { 255 | item.bits = 128; 256 | } 257 | } 258 | else if ( dbgeng.DEBUG_VALUE_VECTOR64 === desc.type ) 259 | { 260 | if ( !child ) 261 | { 262 | item.bits = 64; 263 | } 264 | } 265 | else if ( dbgeng.DEBUG_VALUE_VECTOR128 === desc.type ) 266 | { 267 | if ( !child ) 268 | { 269 | item.bits = 128; 270 | } 271 | } 272 | 273 | return item; 274 | } 275 | exports.findRegister = findRegister; 276 | exports.findReg = findRegister; 277 | 278 | function enumRegister() 279 | { 280 | let count = 0; 281 | 282 | let index = 0; 283 | 284 | let item = null; 285 | 286 | let items = []; 287 | 288 | count = dbgeng.getNumberRegisters(); 289 | 290 | for ( index = 0; index < count; index++) 291 | { 292 | item = findRegister(index); 293 | 294 | items.push(item); 295 | } 296 | 297 | return items; 298 | } 299 | exports.enumRegister = enumRegister; 300 | exports.enumReg = enumRegister; 301 | 302 | function getRegister(name) 303 | { 304 | let item = findRegister(name); 305 | 306 | return item.getValue(); 307 | } 308 | exports.getRegister = getRegister; 309 | exports.getReg = getRegister; 310 | 311 | 312 | function setRegister( name , value ) 313 | { 314 | let reg = findRegister(name); 315 | 316 | return reg.setValue(value); 317 | } 318 | exports.setRegister = setRegister; 319 | exports.setReg = setRegister; 320 | 321 | 322 | 323 | 324 | -------------------------------------------------------------------------------- /src/script/jswd/segment.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | 3 | const typing = require("typing"); 4 | 5 | const dbgeng = require("dbgeng"); 6 | 7 | const fmt = require('fmt'); 8 | 9 | const reg = require('jswd/register'); 10 | 11 | const virtual = require('jswd/virtual'); 12 | 13 | 14 | class Segment 15 | { 16 | constructor(value) { 17 | 18 | this.value = value; 19 | 20 | // base [24 : 32) 21 | const baseHigh = value.slice( 56, 63).toNumber(); 22 | 23 | // G , 24 | this.granularity = value.getBit(55) ; 25 | 26 | // D/B , default operation size , 0 = 16bit , 1 = 32bit 27 | this.db = value.getBit(54) ; 28 | 29 | // L , 64-bit code segment 30 | this.l = value.getBit(53) ; 31 | 32 | // AVL , available for use by system software 33 | this.avl = value.getBit(52) ; 34 | 35 | // [16 : 20) 36 | const limitHigh = value.slice( 48, 52).toNumber(); 37 | 38 | // P, 39 | this.present = value.getBit( 47) ; 40 | 41 | // DPL , descriptor privilege level 42 | this.dpl = value.slice( 45, 47).toNumber(); 43 | 44 | // S , 0 = system , 1 = code or data 45 | this.system = value.getBit( 44); 46 | 47 | // segment type 48 | this.type = value.slice( 40, 44).toNumber(); 49 | 50 | // base [16 : 24) 51 | const baseMid = value.slice( 32, 39).toNumber(); 52 | 53 | // base [0 : 16) 54 | const baseLow = value.slice( 16, 32).toNumber(); 55 | 56 | // limit [0:16) 57 | const limitLow = value.slice( 0, 16).toNumber(); 58 | 59 | // 60 | this.base = ( baseHigh << 24 ) | ( baseMid << 16 ) | baseLow; 61 | 62 | this.limit = ( limitHigh << 16 ) | limitLow; 63 | } 64 | } 65 | exports.Segment = Segment; 66 | 67 | /** 68 | * get segment value 69 | * @param {String|Number} nameOrSelector 70 | * @returns {Uint64} 71 | */ 72 | function getSegment(nameOrSelector) 73 | { 74 | let selector = 0; 75 | 76 | if ( typing.isString(nameOrSelector) ) 77 | { 78 | selector = reg.getRegister(nameOrSelector); 79 | 80 | assert( typing.isNumber(selector) ); 81 | } 82 | else 83 | { 84 | assert( typing.isNumber(nameOrSelector) ); 85 | 86 | selector = nameOrSelector; 87 | } 88 | 89 | let gdtr = reg.getRegister('gdtr'); 90 | 91 | assert( Uint64.isUint64(gdtr) ); 92 | 93 | let index = selector >> 3; 94 | 95 | let offset = index * 8; 96 | 97 | let address = new Uint64( gdtr.add(offset) ); 98 | 99 | return virtual.readUint64LE( address ); 100 | } 101 | exports.getSegment = getSegment; 102 | exports.getSeg = getSegment; 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/script/jswd/symbol.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | 3 | const typing = require("typing"); 4 | 5 | const fmt = require('fmt'); 6 | 7 | const int = require('integer'); 8 | 9 | const Int64 = int.Int64; 10 | 11 | const Uint64 = int.Uint64; 12 | 13 | const dbgeng = require("dbgeng"); 14 | 15 | 16 | // symbol to address 17 | exports.resolve = dbgeng.getOffsetByName; 18 | 19 | // address to symbol 20 | exports.symbolize = dbgeng.getNameByOffset; 21 | 22 | 23 | /** 24 | * 25 | * @param {String} name 26 | * @returns {Number} 27 | */ 28 | function sizeof(name) 29 | { 30 | let info = dbgeng.getSymbolTypeId( name); 31 | 32 | return dbgeng.getTypeSize(info.imageBase , info.typeId); 33 | } 34 | exports.sizeof = sizeof; 35 | 36 | 37 | /** 38 | * 39 | * @param {String} type 40 | * @param {String} field 41 | * @returns {Number} 42 | */ 43 | function fieldOffset( type , field) 44 | { 45 | let info = dbgeng.getSymbolTypeId( type); 46 | 47 | return dbgeng.getFieldOffset( info.imageBase , info.typeId , field); 48 | } 49 | exports.fieldOffset = fieldOffset; 50 | 51 | -------------------------------------------------------------------------------- /src/script/jswd/virtual.js: -------------------------------------------------------------------------------- 1 | const _ = require('underscore'); 2 | 3 | const typing = require("typing"); 4 | 5 | const dbgeng = require("dbgeng"); 6 | 7 | const readerExports = require('jswd/reader'); 8 | 9 | const writerExports = require('jswd/writer'); 10 | 11 | 12 | class Reader 13 | { 14 | constructor() 15 | { 16 | 17 | } 18 | 19 | read(address , buffer) 20 | { 21 | return dbgeng.readVirtual(address , buffer); 22 | } 23 | } 24 | 25 | class Writer 26 | { 27 | constructor() 28 | { 29 | 30 | } 31 | 32 | write(address , buffer) 33 | { 34 | return dbgeng.writeVirtual(address , buffer); 35 | } 36 | } 37 | 38 | 39 | let name = ''; 40 | 41 | let routine = null; 42 | 43 | let reader = new Reader(); 44 | 45 | let writer = new Writer(); 46 | 47 | // for reader 48 | for ( name in readerExports ) 49 | { 50 | routine = readerExports[name]; 51 | 52 | if ( typing.isFunction(routine) ) 53 | { 54 | exports[name] = routine.bind(this , reader); 55 | } 56 | } 57 | 58 | // for writer 59 | for ( name in writerExports ) 60 | { 61 | routine = writerExports[name]; 62 | 63 | if ( typing.isFunction(routine) ) 64 | { 65 | exports[name] = routine.bind(this , writer); 66 | } 67 | } -------------------------------------------------------------------------------- /src/script/jswd/writer.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | 3 | const typing = require("typing"); 4 | 5 | const fmt = require('fmt'); 6 | 7 | const maxStringLength = 65536; 8 | 9 | 10 | /** 11 | * 12 | * @param {Writer} writer 13 | * @param {Uint64} address 14 | * @param {Number} value 15 | * @returns {Number} 16 | */ 17 | function writeFloat32BE(writer , address , value) 18 | { 19 | assert( typing.isNumber(value) ); 20 | 21 | let buffer = new ArrayBuffer(4); 22 | 23 | let view = new DataView(buffer); 24 | 25 | view.setFloat32(0 , value , false); 26 | 27 | return writer.write(address , buffer); 28 | } 29 | exports.writeFloat32BE = writeFloat32BE; 30 | 31 | /** 32 | * 33 | * @param {Writer} writer 34 | * @param {Uint64} address 35 | * @param {Number} value 36 | * @returns {Number} 37 | */ 38 | function writeFloat32LE(writer ,address , value) 39 | { 40 | assert( typing.isNumber(value) ); 41 | 42 | let buffer = new ArrayBuffer(4); 43 | 44 | let view = new DataView(buffer); 45 | 46 | view.setFloat32(0 , value , true); 47 | 48 | return writer.write(address , buffer); 49 | } 50 | exports.writeFloat32LE = writeFloat32LE; 51 | 52 | 53 | /** 54 | * 55 | * @param {Writer} writer 56 | * @param {Uint64} address 57 | * @param {Number} value 58 | * @returns {Number} 59 | */ 60 | function writeFloat64BE(writer ,address , value) 61 | { 62 | assert( typing.isNumber(value) ); 63 | 64 | let buffer = new ArrayBuffer(8); 65 | 66 | let view = new DataView(buffer); 67 | 68 | view.setFloat64(0 , value , false); 69 | 70 | return writer.write(address , buffer); 71 | } 72 | exports.writeFloat64BE = writeFloat64BE; 73 | 74 | /** 75 | * 76 | * @param {Writer} writer 77 | * @param {Uint64} address 78 | * @param {Number} value 79 | * @returns {Number} 80 | */ 81 | function writeFloat64LE(writer ,address , value) 82 | { 83 | assert( typing.isNumber(value) ); 84 | 85 | let buffer = new ArrayBuffer(8); 86 | 87 | let view = new DataView(buffer); 88 | 89 | view.setFloat64( 0 , value , true); 90 | 91 | return writer.write(address , buffer); 92 | } 93 | exports.writeFloat64LE = writeFloat64LE; 94 | 95 | //--------------------------------for signed---------------------------------------------------------------- 96 | 97 | /** 98 | * 99 | * @param {Writer} writer 100 | * @param {Uint64} address 101 | * @param {Number} value 102 | * @returns {Number} 103 | */ 104 | function writeInt8(writer ,address , value) 105 | { 106 | assert( typing.isNumber(value) ); 107 | 108 | let buffer = new ArrayBuffer(1); 109 | 110 | let view = new DataView(buffer); 111 | 112 | view.setInt8(0 , value); 113 | 114 | return writer.write(address , buffer); 115 | } 116 | exports.writeInt8 = writeInt8; 117 | 118 | /** 119 | * 120 | * @param {Writer} writer 121 | * @param {Uint64} address 122 | * @param {Number} value 123 | * @returns {Number} 124 | */ 125 | function writeInt16BE(writer ,address , value) 126 | { 127 | assert( typing.isNumber(value) ); 128 | 129 | let buffer = new ArrayBuffer(2); 130 | 131 | let view = new DataView(buffer); 132 | 133 | view.setInt16( 0 , value , false); 134 | 135 | return writer.write(address , buffer); 136 | } 137 | exports.writeInt16BE = writeInt16BE; 138 | 139 | /** 140 | * 141 | * @param {Writer} writer 142 | * @param {Uint64} address 143 | * @param {Number} value 144 | * @returns {Number} 145 | */ 146 | function writeInt16LE(writer ,address, value) 147 | { 148 | assert( typing.isNumber(value) ); 149 | 150 | let buffer = new ArrayBuffer(2); 151 | 152 | let view = new DataView(buffer); 153 | 154 | view.setInt16( 0 , value , true); 155 | 156 | return writer.write(address , buffer); 157 | } 158 | exports.writeInt16LE = writeInt16LE; 159 | 160 | 161 | /** 162 | * 163 | * @param {Writer} writer 164 | * @param {Uint64} address 165 | * @param {Number} value 166 | * @returns {Number} 167 | */ 168 | function writeInt32BE(writer ,address, value) 169 | { 170 | assert( typing.isNumber(value) ); 171 | 172 | let buffer = new ArrayBuffer(4); 173 | 174 | let view = new DataView(buffer); 175 | 176 | view.setInt32( 0 , value , false); 177 | 178 | return writer.write(address , buffer); 179 | } 180 | exports.writeInt32BE = writeInt32BE; 181 | 182 | /** 183 | * 184 | * @param {Writer} writer 185 | * @param {Uint64} address 186 | * @param {Number} value 187 | * @returns {Number} 188 | */ 189 | function writeInt32LE(writer ,address, value) 190 | { 191 | assert( typing.isNumber(value) ); 192 | 193 | let buffer = new ArrayBuffer(4); 194 | 195 | let view = new DataView(buffer); 196 | 197 | view.setInt32( 0 , value , true); 198 | 199 | return writer.write(address , buffer); 200 | } 201 | exports.writeInt32LE = writeInt32LE; 202 | 203 | 204 | /** 205 | * 206 | * @param {Writer} writer 207 | * @param {Uint64} address 208 | * @param {Int64} value 209 | * @returns {Number} 210 | */ 211 | function writeInt64BE(writer ,address , value) 212 | { 213 | let argValue = 0; 214 | 215 | if ( Int64.isInt64(value) ) 216 | { 217 | argValue = value; 218 | } 219 | else 220 | { 221 | argValue = new Int64(value); 222 | } 223 | 224 | let buffer = new ArrayBuffer(8); 225 | 226 | let view = new DataView(buffer); 227 | 228 | view.setInt32( 4 , argValue.low , false ); 229 | 230 | view.setInt32( 0 , argValue.high , false ); 231 | 232 | return writer.write(address , buffer); 233 | } 234 | exports.writeInt64BE = writeInt64BE; 235 | 236 | /** 237 | * 238 | * @param {Writer} writer 239 | * @param {Uint64} address 240 | * @param {Int64} value 241 | * @returns {Number} 242 | */ 243 | function writeInt64LE(writer ,address, value ) 244 | { 245 | let argValue = 0; 246 | 247 | if ( Int64.isInt64(value) ) 248 | { 249 | argValue = value; 250 | } 251 | else 252 | { 253 | argValue = new Int64(value); 254 | } 255 | 256 | let buffer = new ArrayBuffer(8); 257 | 258 | let view = new DataView(buffer); 259 | 260 | view.setInt32( 0 , argValue.low , true ); 261 | 262 | view.setInt32( 4 , argValue.high , true ); 263 | 264 | return writer.write(address , buffer); 265 | } 266 | exports.writeInt64LE = writeInt64LE; 267 | 268 | 269 | 270 | //--------------------------------for unsigned---------------------------------------------------------------- 271 | 272 | 273 | /** 274 | * 275 | * @param {Writer} writer 276 | * @param {Uint64} address 277 | * @param {Number} value 278 | * @returns {Number} 279 | */ 280 | function writeUint8(writer ,address , value) 281 | { 282 | let buffer = new ArrayBuffer(1); 283 | 284 | let view = new DataView(buffer); 285 | 286 | view.setUint8(0 , value); 287 | 288 | return writer.write(address , buffer); 289 | } 290 | exports.writeUint8 = writeUint8; 291 | 292 | /** 293 | * 294 | * @param {Writer} writer 295 | * @param {Uint64} address 296 | * @param {Number} value 297 | * @returns {Number} 298 | */ 299 | function writeUint16BE(writer ,address, value) 300 | { 301 | let buffer = new ArrayBuffer(2); 302 | 303 | let view = new DataView(buffer); 304 | 305 | view.setUint16(0 , value , false); 306 | 307 | return writer.write(address , buffer); 308 | } 309 | exports.writeUint16BE = writeUint16BE; 310 | 311 | /** 312 | * 313 | * @param {Writer} writer 314 | * @param {Uint64} address 315 | * @param {Number} value 316 | * @returns {Number} 317 | */ 318 | function writeUint16LE(writer ,address, value) 319 | { 320 | let buffer = new ArrayBuffer(2); 321 | 322 | let view = new DataView(buffer); 323 | 324 | view.setUint16(0 , value , true); 325 | 326 | return writer.write(address , buffer); 327 | } 328 | exports.writeUint16LE = writeUint16LE; 329 | 330 | 331 | /** 332 | * 333 | * @param {Writer} writer 334 | * @param {Uint64} address 335 | * @param {Number} value 336 | * @returns {Number} 337 | */ 338 | function writeUint32BE(writer ,address, value) 339 | { 340 | let buffer = new ArrayBuffer(4); 341 | 342 | let view = new DataView(buffer); 343 | 344 | view.setUint32(0 , value , false); 345 | 346 | return writer.write(address , buffer); 347 | } 348 | exports.writeUint32BE = writeUint32BE; 349 | 350 | /** 351 | * 352 | * @param {Writer} writer 353 | * @param {Uint64} address 354 | * @param {Number} value 355 | * @returns {Number} 356 | */ 357 | function writeUint32LE(writer ,address, value ) 358 | { 359 | let buffer = new ArrayBuffer(4); 360 | 361 | let view = new DataView(buffer); 362 | 363 | view.setUint32(0 , value , true); 364 | 365 | return writer.write(address , buffer); 366 | } 367 | exports.writeUint32LE = writeUint32LE; 368 | 369 | 370 | /** 371 | * 372 | * @param {Writer} writer 373 | * @param {Uint64} address 374 | * @param {Uint64} value 375 | * @returns {Number} 376 | */ 377 | function writeUint64BE(writer ,address , value) 378 | { 379 | let argValue = 0; 380 | 381 | if ( Uint64.isUint64(value) ) 382 | { 383 | argValue = value; 384 | } 385 | else 386 | { 387 | argValue = new Uint64(value); 388 | } 389 | 390 | let buffer = new ArrayBuffer(8); 391 | 392 | let view = new DataView(buffer); 393 | 394 | view.setUint32( 4 , argValue.low, false ); 395 | 396 | view.setUint32( 0 , argValue.high, false ); 397 | 398 | return writer.write(address , buffer); 399 | } 400 | exports.writeUint64BE = writeUint64BE; 401 | 402 | /** 403 | * 404 | * @param {Writer} writer 405 | * @param {Uint64} address 406 | * @param {Uint64} value 407 | * @returns {Number} 408 | */ 409 | function writeUint64LE(writer ,address, value) 410 | { 411 | let argValue = 0; 412 | 413 | if ( Uint64.isUint64(value) ) 414 | { 415 | argValue = value; 416 | } 417 | else 418 | { 419 | argValue = new Uint64(value); 420 | } 421 | 422 | let buffer = new ArrayBuffer(8); 423 | 424 | let view = new DataView(buffer); 425 | 426 | view.setUint32( 0 , argValue.low, true ); 427 | 428 | view.setUint32( 4 , argValue.high, true ); 429 | 430 | return writer.write(address , buffer); 431 | } 432 | exports.writeUint64LE = writeUint64LE; 433 | 434 | 435 | //--------------------------------for string---------------------------------------------------------------- 436 | 437 | 438 | /** 439 | * 440 | * @param {Writer} writer 441 | * @param {Uint64} address 442 | * @param {String} value 443 | * @returns {Number} 444 | */ 445 | function writeString(writer , address , value) 446 | { 447 | let encoder = null; 448 | 449 | let data = null; 450 | 451 | encoder = new TextEncoder('utf8'); 452 | 453 | data = encoder.encode(value); 454 | 455 | return writer.write(address , data.buffer); 456 | } 457 | exports.writeString = writeString; 458 | 459 | /** 460 | * 461 | * @param {Writer} writer 462 | * @param {Uint64} address 463 | * @param {String} value 464 | * @returns {Number} 465 | */ 466 | function writeWideString(writer ,address , value) 467 | { 468 | let encoder = null; 469 | 470 | let data = null; 471 | 472 | encoder = new TextEncoder('utf16'); 473 | 474 | data = encoder.encode(value); 475 | 476 | return writer.write(address , data.buffer); 477 | } 478 | exports.writeWideString = writeWideString; 479 | 480 | 481 | -------------------------------------------------------------------------------- /src/util/util_string.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file util_string.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | std::vector UtilCmdlineToArgv(const std::string &cmdline) 18 | { 19 | HRESULT result = E_FAIL; 20 | 21 | HRESULT hr = E_FAIL; 22 | 23 | LPWSTR *wideArgv = nullptr; 24 | 25 | int i = 0; 26 | 27 | std::wstring wideArg; 28 | 29 | int argc = 0; 30 | 31 | std::string arg; 32 | 33 | std::vector argv; 34 | 35 | do 36 | { 37 | if (!cmdline.empty()) 38 | { 39 | std::wstring_convert> converter; 40 | 41 | std::wstring wideCmdline = converter.from_bytes(cmdline.c_str()); 42 | 43 | wideArgv = CommandLineToArgvW(wideCmdline.c_str(), &argc); 44 | if (nullptr == wideArgv) 45 | { 46 | break; 47 | } 48 | 49 | for (i = 0; i < argc; i++) 50 | { 51 | wideArg = std::wstring(wideArgv[i]); 52 | 53 | arg = converter.to_bytes(wideArg.c_str()); 54 | 55 | argv.push_back(arg); 56 | } 57 | } 58 | 59 | result = S_OK; 60 | 61 | } while (false); 62 | 63 | if (nullptr != wideArgv) 64 | { 65 | LocalFree(wideArgv); 66 | wideArgv = nullptr; 67 | } 68 | 69 | return argv; 70 | } -------------------------------------------------------------------------------- /src/util/util_string.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file util_string.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_UTIL_STRING_HEADER_FILE__ 10 | #define __MY_UTIL_STRING_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | 13 | #include 14 | 15 | std::vector UtilCmdlineToArgv(const std::string &cmdline); 16 | 17 | //////////////////////////////////////////////////// 18 | #endif //__MY_UTIL_STRING_HEADER_FILE__ 19 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file version.h 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | 7 | */ 8 | 9 | #ifndef __MY_VERSION_HEADER_FILE__ 10 | #define __MY_VERSION_HEADER_FILE__ 11 | //////////////////////////////////////////////////// 12 | #ifdef __cplusplus 13 | extern "C" 14 | { 15 | #endif 16 | //////////////////////////////////////////////////// 17 | 18 | #include 19 | 20 | #ifndef _VERSION_HELPER_MAKE_ULONG64 21 | #define _VERSION_HELPER_MAKE_ULONG64(low, high) \ 22 | ((ULONG64)(((ULONG)((ULONG64)(low)&0xffffffff)) | ((ULONG64)((ULONG)((ULONG64)(high)&0xffffffff))) << 32)) 23 | #endif // #ifndef _VERSION_HELPER_MAKE_ULONG64 24 | 25 | #ifndef _VERSION_HELPER_MAKE_ULONG 26 | #define _VERSION_HELPER_MAKE_ULONG(low, high) \ 27 | ((ULONG)(((USHORT)((ULONG_PTR)(low)&0xffff)) | ((ULONG)((USHORT)((ULONG_PTR)(high)&0xffff))) << 16)) 28 | #endif // #ifndef _VERSION_HELPER_MAKE_ULONG 29 | 30 | #ifndef _VERSION_HELPER_MAKE_USHORT 31 | #define _VERSION_HELPER_MAKE_USHORT(low, high) ((USHORT)(((UCHAR)(low)) | ((USHORT)((UCHAR)(high))) << 8)) 32 | #endif // #ifndef _VERSION_HELPER_MAKE_USHORT 33 | 34 | #ifndef _VERSION_HELPER_MAKE_VERSION 35 | #define _VERSION_HELPER_MAKE_VERSION(v1, v2, v3, v4) \ 36 | _VERSION_HELPER_MAKE_ULONG64(_VERSION_HELPER_MAKE_ULONG(v4, v3), _VERSION_HELPER_MAKE_ULONG(v2, v1)) 37 | #endif // #ifndef _VERSION_HELPER_MAKE_VERSION 38 | 39 | // Version 40 | #ifndef _VERSION_HELPER_MARCO_STRING_2 41 | #define _VERSION_HELPER_MARCO_STRING_2(x) #x 42 | #endif // _VERSION_HELPER_MARCO_STRING_2 43 | 44 | #ifndef _VERSION_HELPER_MARCO_STRING 45 | #define _VERSION_HELPER_MARCO_STRING(x) _VERSION_HELPER_MARCO_STRING_2(x) 46 | #endif // _VERSION_HELPER_MARCO_STRING 47 | 48 | ////////////////////////////////////////////////////////////////////////// 49 | 50 | #define MY_VERSION_MAJOR 0 51 | 52 | #define MY_VERSION_MINOR 0 53 | 54 | #define MY_BANNER "Windbg javascript extension for hacker , a gift from tinysec.\n" 55 | 56 | #define MY_VERSION_PART_1 MY_VERSION_MAJOR 57 | 58 | #define MY_VERSION_PART_2 MY_VERSION_MINOR 59 | 60 | #define MY_VERSION_PART_3 0 61 | 62 | #define MY_VERSION_PART_4 1001 63 | 64 | ////////////////////////////////////////////////////////////////////////// 65 | 66 | #define MY_VERSION_NUMBER \ 67 | _VERSION_HELPER_MAKE_VERSION(MY_VERSION_PART_1, MY_VERSION_PART_2, MY_VERSION_PART_3, MY_VERSION_PART_4) 68 | 69 | #define MY_VERSION_DOT_STRING \ 70 | _VERSION_HELPER_MARCO_STRING(MY_VERSION_PART_1.MY_VERSION_PART_2.MY_VERSION_PART_3.MY_VERSION_PART_4) 71 | 72 | #define MY_VERSION_COMMA_STRING MY_VERSION_PART_1, MY_VERSION_PART_2, MY_VERSION_PART_3, MY_VERSION_PART_4 73 | 74 | #define MY_VERSION_INTERNALNAME "jswd.dll\0" 75 | 76 | #if defined _WIN64 77 | 78 | #ifdef _DEBUG 79 | #define MY_VERSION_COMMENTS "jswd (amd64) (debug)\0" 80 | #else 81 | #define MY_VERSION_COMMENTS "jswd (amd64)\0" 82 | #endif 83 | 84 | #elif defined _ARM64_ 85 | 86 | #ifdef _DEBUG 87 | #define MY_VERSION_COMMENTS "js (arm64) (debug)\0" 88 | #else 89 | #define MY_VERSION_COMMENTS "jswd (arm64)\0" 90 | #endif 91 | 92 | #else 93 | 94 | #ifdef _DEBUG 95 | #define MY_VERSION_COMMENTS "jswd (i386) (debug)\0" 96 | #else 97 | #define MY_VERSION_COMMENTS "jswd\0" 98 | #endif 99 | 100 | #endif // #ifdef _WIN64 101 | 102 | #define MY_VERSION_COMPANYNAME "github.com/tinysec\0" 103 | 104 | #define MY_VERSION_FILEDESCRIPTION MY_VERSION_COMMENTS 105 | 106 | #define MY_VERSION_LEGALCOPYRIGHT "tinysec.net. All Rights Reserved\0" 107 | 108 | #define MY_VERSION_LEGALTRADEMARKS "Powered by TinySec!\0" 109 | 110 | #define MY_VERSION_PRODUCTNAME "jswd\0" 111 | 112 | #define MY_VERSION_FILEVERSION MY_VERSION_DOT_STRING 113 | 114 | #define MY_VERSION_ORIGINALFILENAME MY_VERSION_INTERNALNAME 115 | #define MY_VERSION_PRIVATEBUILD MY_VERSION_DOT_STRING 116 | 117 | #define MY_VERSION_PRODUCTVERSION MY_VERSION_DOT_STRING 118 | #define MY_VERSION_SPECIALBUILD MY_VERSION_DOT_STRING 119 | 120 | //////////////////////////////////////////////////// 121 | #ifdef __cplusplus 122 | } // extern "C" 123 | #endif 124 | //////////////////////////////////////////////////// 125 | #endif //__MY_VERSION_HEADER_FILE__ 126 | -------------------------------------------------------------------------------- /src/version.rc: -------------------------------------------------------------------------------- 1 | #include "version.h" 2 | #include 3 | #include 4 | 5 | VS_VERSION_INFO VERSIONINFO FILEVERSION MY_VERSION_COMMA_STRING PRODUCTVERSION MY_VERSION_COMMA_STRING FILEFLAGSMASK 6 | VS_FFI_FILEFLAGSMASK FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK 7 | "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "Comments", 8 | MY_VERSION_COMMENTS VALUE "CompanyName", MY_VERSION_COMPANYNAME VALUE "FileDescription", 9 | MY_VERSION_FILEDESCRIPTION VALUE "FileVersion", MY_VERSION_FILEVERSION VALUE "InternalName", 10 | MY_VERSION_INTERNALNAME VALUE "LegalCopyright", MY_VERSION_LEGALCOPYRIGHT VALUE "LegalTrademarks", 11 | MY_VERSION_LEGALTRADEMARKS VALUE "OriginalFilename", MY_VERSION_ORIGINALFILENAME VALUE "PrivateBuild", 12 | MY_VERSION_PRIVATEBUILD VALUE "ProductName", MY_VERSION_PRODUCTNAME VALUE "ProductVersion", 13 | MY_VERSION_PRODUCTVERSION VALUE "SpecialBuild", 14 | MY_VERSION_SPECIALBUILD END END 15 | 16 | BLOCK "VarFileInfo" BEGIN VALUE "Translation", 17 | 0x409, 1200 END END 18 | -------------------------------------------------------------------------------- /tests/test.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file test_foobar.cpp 3 | * @author tinysec 4 | * @brief 5 | * @version 0.0.1 6 | * 22-12-21 init 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "src/extension.h" 14 | 15 | #include "src/entrypoint.h" 16 | 17 | #include "command/commands.h" 18 | 19 | #include "callbacks/standard_output_callbacks.h" 20 | 21 | int main(int argc, char **argv) 22 | { 23 | HRESULT hr = S_FALSE; 24 | 25 | ULONG version = 0; 26 | 27 | ULONG flags = 0; 28 | 29 | JsErrorCode errorCode = JsErrorFatal; 30 | 31 | IDebugClient *debugClient = nullptr; 32 | 33 | IDebugControl *debugControl = nullptr; 34 | 35 | IDebugSymbols *debugSymbols = nullptr; 36 | 37 | StandardOutputCallbacks *standardOutputCallbacks = nullptr; 38 | 39 | StandardEventCallbacks *standardEventCallbacks = nullptr; 40 | 41 | do 42 | { 43 | if (!SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)) ) 44 | { 45 | break; 46 | } 47 | 48 | hr = DebugCreate(__uuidof(IDebugClient), (PVOID *)&(debugClient)); 49 | if (!SUCCEEDED(hr)) 50 | { 51 | break; 52 | } 53 | 54 | hr = debugClient->QueryInterface(__uuidof(IDebugControl), (PVOID *)&(debugControl)); 55 | if (!SUCCEEDED(hr)) 56 | { 57 | break; 58 | } 59 | 60 | hr = debugClient->QueryInterface(__uuidof(IDebugSymbols), (PVOID *)&(debugSymbols)); 61 | if (!SUCCEEDED(hr)) 62 | { 63 | break; 64 | } 65 | 66 | 67 | standardOutputCallbacks = new StandardOutputCallbacks(); 68 | 69 | hr = debugClient->SetOutputCallbacks(standardOutputCallbacks); 70 | if (!SUCCEEDED(hr)) 71 | { 72 | break; 73 | } 74 | 75 | // set event callbacks 76 | standardEventCallbacks = new StandardEventCallbacks(); 77 | 78 | hr = debugClient->SetEventCallbacks(standardEventCallbacks); 79 | if (!SUCCEEDED(hr)) 80 | { 81 | break; 82 | } 83 | 84 | hr = debugSymbols->SetSymbolPath("D:\\sys\\symbols"); 85 | if (!SUCCEEDED(hr)) 86 | { 87 | break; 88 | } 89 | 90 | 91 | hr = DebugExtensionInitialize(&version, &flags); 92 | if (!SUCCEEDED(hr)) 93 | { 94 | break; 95 | } 96 | 97 | hr = debugClient->OpenDumpFile("D:\\sys\\crash\\MEMORY.DMP"); 98 | if (!SUCCEEDED(hr)) 99 | { 100 | break; 101 | } 102 | hr = debugControl->Execute( 0 , ".reload nt" , 0); 103 | if (!SUCCEEDED(hr)) 104 | { 105 | break; 106 | } 107 | 108 | 109 | // Set to zero. There are currently no flags that can be used in this parameter. 110 | hr = debugControl->WaitForEvent(0, INFINITE); 111 | if (!SUCCEEDED(hr)) 112 | { 113 | break; 114 | } 115 | 116 | hr = jsrun(debugClient, "D:\\code\\jswd\\jstests\\test.js"); 117 | if (!SUCCEEDED(hr)) 118 | { 119 | 120 | break; 121 | } 122 | 123 | } while (false); 124 | 125 | DebugExtensionUninitialize(); 126 | 127 | if (nullptr != debugClient) 128 | { 129 | debugClient->SetOutputCallbacks(nullptr); 130 | 131 | // set event callbacks 132 | debugClient->SetEventCallbacks(nullptr); 133 | 134 | debugClient->Release(); 135 | debugClient = nullptr; 136 | } 137 | 138 | if (nullptr != debugControl) 139 | { 140 | debugControl->Release(); 141 | debugControl = nullptr; 142 | } 143 | 144 | if (nullptr != standardOutputCallbacks) 145 | { 146 | standardOutputCallbacks->Release(); 147 | standardOutputCallbacks = nullptr; 148 | } 149 | 150 | if (nullptr != standardEventCallbacks) 151 | { 152 | standardEventCallbacks->Release(); 153 | standardEventCallbacks = nullptr; 154 | } 155 | 156 | CoUninitialize(); 157 | 158 | return 0; 159 | } --------------------------------------------------------------------------------