├── .appveyor.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── build.sh ├── build_codelite.sh ├── build_qt4.sh ├── disasm-cli ├── CMakeLists.txt ├── main.cpp └── main.h └── disasm ├── CMakeLists.txt ├── CodeBlock.cpp ├── Context.cpp ├── DisasmBase.cpp ├── DisasmChunk.cpp ├── DisasmChunkBuf.cpp ├── ExeDisasm.h ├── FuncNameManager.cpp ├── Tracer.cpp ├── Util.cpp ├── Util.h ├── cdis ├── CDisasm.cpp ├── CDisasm.h ├── CapstoneChunk.cpp ├── CapstoneChunk.h └── ExeDisasm.h ├── dos ├── DosDisasm.cpp └── DosTracer.cpp ├── include ├── AddrConverter.h ├── CodeBlock.h ├── Context.h ├── DisasmBase.h ├── DisasmChunk.h ├── DisasmChunkBuf.h ├── FuncNameManager.h ├── MnemType.h ├── TargetValue.h ├── Tracer.h ├── beardisasm.h ├── dos │ ├── DosDisasm.h │ └── DosTracer.h └── pe │ ├── PeDataFetcher.h │ ├── PeDisasm.h │ └── PeTracer.h ├── pe ├── PeDisasm.cpp └── PeTracer.cpp └── udis ├── ExeDisasm.h ├── UDisasm.cpp ├── UDisasm.h ├── UdisChunk.cpp └── UdisChunk.h /.appveyor.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - Visual Studio 2015 3 | 4 | platform: x64 5 | - x64 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | install: 12 | - git submodule update --init --recursive 13 | - set PATH=C:\Program Files\CMake\bin;%PATH% 14 | 15 | build: 16 | verbosity: detailed 17 | 18 | configuration: 19 | - Release 20 | 21 | environment: 22 | artifactName: $(APPVEYOR_PROJECT_NAME)-$(APPVEYOR_REPO_COMMIT)-$(CONFIGURATION) 23 | matrix: 24 | - env_arch: "x64" 25 | QT5: C:\Qt\5.11\msvc2015_64 26 | - env_arch: "x86" 27 | QT5: C:\Qt\5.11\msvc2015 28 | 29 | before_build: 30 | - set PATH=%PATH%;%QT5%\bin;%QT5%\lib\cmake 31 | - set Qt5Core_DIR=%QT5% 32 | - mkdir build 33 | - cd build 34 | - if [%env_arch%]==[x64] ( 35 | cmake .. -A x64 ) 36 | - if [%env_arch%]==[x86] ( 37 | cmake .. ) 38 | 39 | build_script: 40 | - cmake --build . --config %CONFIGURATION% 41 | 42 | after_build: 43 | - mkdir %artifactName% 44 | - cp -r disasm-cli/%CONFIGURATION%/* %artifactName% 45 | - cp %QT5%\bin\Qt5Core.dll %artifactName% 46 | 47 | artifacts: 48 | - path: build\%artifactName% 49 | 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | build_qt4/ 3 | 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "bearparser"] 2 | path = bearparser 3 | url = https://github.com/hasherezade/bearparser.git 4 | [submodule "capstone"] 5 | path = capstone 6 | url = https://github.com/aquynh/capstone.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | project (beardisasm) 3 | 4 | SET(COMMIT_HASH "" CACHE STRING "Commit Hash") 5 | 6 | # modules: 7 | set ( M_BEARPARSER "bearparser/parser" ) 8 | set ( M_MINIDIS "disasm" ) 9 | set ( M_COMMANDER "vidi" ) 10 | set ( M_CAPSTONE "capstone" ) 11 | set ( M_UDIS86 "udis86" ) 12 | 13 | # modules paths: 14 | set (CAPSTONE_DIR "${CMAKE_SOURCE_DIR}/${M_CAPSTONE}" CACHE PATH "Capstone main path") 15 | set (CAPSTONE_INC "${CAPSTONE_DIR}/include" CACHE PATH "Capstone include path") 16 | 17 | #capstone options: 18 | option(CAPSTONE_BUILD_STATIC_RUNTIME "Embed static runtime" OFF) 19 | option(CAPSTONE_BUILD_STATIC "Build static library" ON) 20 | option(CAPSTONE_BUILD_SHARED "Build shared library" OFF) 21 | option(CAPSTONE_BUILD_DIET "Build diet library" OFF) 22 | option(CAPSTONE_BUILD_TESTS "Build tests" OFF) 23 | option(CAPSTONE_USE_DEFAULT_ALLOC "Use default memory allocation functions" ON) 24 | 25 | option(CAPSTONE_ARM_SUPPORT "ARM support" OFF) 26 | option(CAPSTONE_ARM64_SUPPORT "ARM64 support" OFF) 27 | option(CAPSTONE_MIPS_SUPPORT "MIPS support" OFF) 28 | option(CAPSTONE_PPC_SUPPORT "PowerPC support" OFF) 29 | option(CAPSTONE_SPARC_SUPPORT "Sparc support" OFF) 30 | option(CAPSTONE_SYSZ_SUPPORT "SystemZ support" OFF) 31 | option(CAPSTONE_XCORE_SUPPORT "XCore support" OFF) 32 | option(CAPSTONE_X86_SUPPORT "x86 support" ON) 33 | option(CAPSTONE_X86_REDUCE "x86 with reduce instruction sets to minimize library" OFF) 34 | option(CAPSTONE_X86_ATT_DISABLE "Disable x86 AT&T syntax" ON) 35 | 36 | option(CAPSTONE_M68K_SUPPORT "M68K support" OFF) 37 | option(CAPSTONE_MOS65XX_SUPPORT "MOS65XX support" OFF) 38 | option(CAPSTONE_SH_SUPPORT "SH support" OFF) 39 | option(CAPSTONE_M680X_SUPPORT "M680X support" OFF) 40 | 41 | option(CAPSTONE_TMS320C64X_SUPPORT "TMS320C64X support" OFF) 42 | option(CAPSTONE_EVM_SUPPORT "EVM support" OFF) 43 | option(CAPSTONE_WASM_SUPPORT "WASM support" OFF) 44 | option(CAPSTONE_BPF_SUPPORT "BPF support" OFF) 45 | option(CAPSTONE_RISCV_SUPPORT "RISCV support" OFF) 46 | 47 | #project options 48 | option(USE_UDIS86 "Build with udis86" OFF) 49 | option(USE_QT4 "Use Qt4 (Qt5 by default)" OFF ) 50 | 51 | set( UDIS86_DIR "${CMAKE_SOURCE_DIR}/${M_UDIS86}" CACHE PATH "Udis86 main path") 52 | 53 | set (PARSER_DIR "${CMAKE_SOURCE_DIR}/${M_BEARPARSER}" CACHE PATH "BearParser main path") 54 | set (PARSER_INC "${PARSER_DIR}/include" CACHE PATH "BearParser include path") 55 | 56 | set (MINIDIS_DIR "${CMAKE_SOURCE_DIR}/${M_MINIDIS}" CACHE PATH "MiniDis main path") 57 | set (COMMANDER_DIR "${CMAKE_SOURCE_DIR}/${M_COMMANDER}" CACHE PATH "Tester main path") 58 | 59 | # Add sub-directories 60 | # 61 | # libs 62 | if (VIDI_USE_UDIS86) 63 | add_subdirectory(${M_UDIS86}) 64 | set(UDIS86_LIB $ CACHE PATH "Udis86 library path") 65 | endif () 66 | 67 | add_subdirectory (${M_BEARPARSER}) 68 | set (PARSER_LIB $ CACHE PATH "BearParser library path") 69 | 70 | add_subdirectory (${M_MINIDIS}) 71 | set (MINIDIS_LIB $ CACHE PATH "MiniDisasm library path") 72 | 73 | add_subdirectory (${CAPSTONE_DIR}) 74 | include_directories (${CAPSTONE_INC}) 75 | set (CAPSTONE_LIB $ CACHE PATH CapstoneLib) 76 | 77 | add_subdirectory (disasm-cli) 78 | 79 | add_dependencies(disasm-cli bearparser capstone mini_disasm) 80 | 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # beardisasm 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/sdnewxqqd9c1j7xw?svg=true)](https://ci.appveyor.com/project/hasherezade/beardisasm) 4 | 5 | A wrapper for capstone + bearparser 6 | 7 | ## Clone 8 | 9 | Clone the project along with its submodules: 10 | 11 | ```console 12 | git clone --recursive https://github.com/hasherezade/beardisasm.git 13 | ``` 14 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Trying to autobuild minidis..." 3 | 4 | #QT check 5 | 6 | QT_VER=`qmake -v` 7 | str=$QT_VER 8 | substr="Qt version 5" 9 | 10 | echo $QT_VER 11 | if [[ $str == *"$substr"* ]]; then 12 | echo "[+] Qt5 found!" 13 | else 14 | str2=`whereis qt5` 15 | substr2="/qt5" 16 | if [[ $str2 == *"$substr2"* ]]; then 17 | echo "[+] Qt5 found!" 18 | else 19 | echo "Install Qt5 SDK first" 20 | exit -1 21 | fi 22 | fi 23 | 24 | CMAKE_VER=$(cmake --version) 25 | CMAKEV="cmake version" 26 | if echo "$CMAKE_VER" | grep -q "$CMAKEV"; then 27 | echo "[+] CMake found!" 28 | else 29 | echo "[-] CMake NOT found!" 30 | echo "Install cmake first" 31 | exit -1 32 | fi 33 | 34 | mkdir build 35 | echo "[+] build directory created" 36 | cd build 37 | mkdir $(pwd)/out 38 | cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/out/ .. 39 | cmake --build . --target install --config Release 40 | 41 | 42 | -------------------------------------------------------------------------------- /build_codelite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Trying to autobuild minidis..." 3 | 4 | #QT check 5 | 6 | QT_VER=`qmake -v` 7 | str=$QT_VER 8 | substr="Qt version 5" 9 | 10 | echo $QT_VER 11 | if [[ $str == *"$substr"* ]]; then 12 | echo "[+] Qt5 found!" 13 | else 14 | str2=`whereis qt5` 15 | substr2="/qt5" 16 | if [[ $str2 == *"$substr2"* ]]; then 17 | echo "[+] Qt5 found!" 18 | else 19 | echo "Install Qt5 SDK first" 20 | exit -1 21 | fi 22 | fi 23 | 24 | CMAKE_VER=$(cmake --version) 25 | CMAKEV="cmake version" 26 | if echo "$CMAKE_VER" | grep -q "$CMAKEV"; then 27 | echo "[+] CMake found!" 28 | else 29 | echo "[-] CMake NOT found!" 30 | echo "Install cmake first" 31 | exit -1 32 | fi 33 | 34 | mkdir build 35 | echo "[+] build directory created" 36 | cd build 37 | mkdir $(pwd)/out 38 | cmake -G "CodeLite - Unix Makefiles" -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/out/ .. 39 | cmake --build . --target install --config Release 40 | 41 | 42 | -------------------------------------------------------------------------------- /build_qt4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Trying to autobuild bearparser..." 3 | 4 | #QT check 5 | 6 | QT_VER=`qmake -v` 7 | str=$QT_VER 8 | substr="Qt version 4" 9 | 10 | echo $QT_VER 11 | if [[ $str == *"$substr"* ]]; then 12 | echo "[+] Qt4 found!" 13 | else 14 | str2=`whereis qt4` 15 | substr2="lib" 16 | if [[ $str2 == *"$substr2"* ]]; then 17 | echo "[+] Qt4 found!" 18 | else 19 | echo "Install Qt4 SDK first" 20 | exit -1 21 | fi 22 | fi 23 | 24 | CMAKE_VER=`cmake --version` 25 | CMAKEV="cmake version" 26 | if echo "$CMAKE_VER" | grep -q "$CMAKEV"; then 27 | echo "[+] CMake found!" 28 | else 29 | echo "[-] CMake NOT found!" 30 | echo "Install cmake first" 31 | exit -1 32 | fi 33 | 34 | BUILD_DIR=build_qt4 35 | 36 | mkdir $BUILD_DIR 37 | echo "[+] build directory created" 38 | cd $BUILD_DIR 39 | cmake -G "CodeLite - Unix Makefiles" -DUSE_QT4=ON -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/out/ .. 40 | cmake --build . --target install 41 | 42 | -------------------------------------------------------------------------------- /disasm-cli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | 3 | SET(COMMIT_HASH "test" CACHE STRING "Project build info") 4 | message("COMMIT_HASH=${COMMIT_HASH}") 5 | 6 | project (disasm-cli) 7 | find_package(Qt5Core REQUIRED) 8 | 9 | include_directories ( ${PARSER_INC} ) 10 | include_directories ( ${MINIDIS_DIR}/include ) 11 | 12 | if(USE_QT4) 13 | add_compile_definitions(WITH_QT4) 14 | find_package (Qt4 REQUIRED) 15 | include_directories( ${QT_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR} ) 16 | INCLUDE( ${QT_USE_FILE} ) 17 | ADD_DEFINITIONS( ${QT_DEFINITIONS} ) 18 | else() 19 | add_compile_definitions(WITH_QT5) 20 | find_package(Qt5Core REQUIRED) 21 | get_target_property(QtCore_location Qt5::Core LOCATION) 22 | endif() 23 | 24 | set ( srcs 25 | main.cpp 26 | ) 27 | 28 | set ( hdrs 29 | main.h 30 | ) 31 | 32 | add_definitions(-DCOMMIT_HASH=${COMMIT_HASH}) 33 | 34 | add_executable (${PROJECT_NAME} ${srcs} ${hdrs} ) 35 | 36 | if(USE_QT4) 37 | target_link_libraries ( ${PROJECT_NAME} ${QT_QTCORE_LIBRARIES} ) 38 | else() 39 | target_link_libraries( ${PROJECT_NAME} Qt5::Core) 40 | endif() 41 | 42 | 43 | if (USE_UDIS86) 44 | target_link_libraries (${PROJECT_NAME} ${MINIDIS_LIB} ${PARSER_LIB} ${UDIS86_LIB}) 45 | MESSAGE( "Compiling using udis86" ) 46 | else() 47 | target_link_libraries (${PROJECT_NAME} ${MINIDIS_LIB} ${PARSER_LIB} ${CAPSTONE_LIB}) 48 | MESSAGE( "Compiling using capstone" ) 49 | endif() 50 | 51 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) 52 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) 53 | 54 | 55 | #install 56 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 57 | 58 | 59 | -------------------------------------------------------------------------------- /disasm-cli/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define MINBUF 0x200 8 | 9 | using namespace minidis; 10 | 11 | FileView* tryLoading(QString &fName) 12 | { 13 | FileView *fileView = NULL; 14 | bufsize_t maxMapSize = FILE_MAXSIZE; 15 | do { 16 | if (!QFile::exists(fName)) { 17 | std::cerr << "[ERROR] " << "The file does not exist" << std::endl; 18 | break; 19 | } 20 | try { 21 | fileView = new FileView(fName, maxMapSize); 22 | } catch (BufferException &e1) { 23 | std::cerr << "[ERROR] " << e1.what() << std::endl; 24 | if (maxMapSize == 0) break; 25 | } 26 | } while (!fileView); 27 | 28 | return fileView; 29 | } 30 | 31 | void disasmPeFile(PEFile *exe, offset_t func_offset) 32 | { 33 | if (!exe) return; 34 | 35 | const minidis::DisasmSettings basicSettings(0, false, true); 36 | 37 | minidis::PeDisasm disasm1(exe); 38 | disasm1.init(func_offset); 39 | if (!disasm1.fillTable(basicSettings)) return; 40 | for (size_t i = 0; ; i++) { 41 | DisasmChunk* chunk = disasm1.getChunkAtIndex(i); 42 | if (!chunk) break; 43 | std::cout << std::hex << disasm1.getOffset(i, Executable::VA) 44 | << " : " 45 | << chunk->toString().toStdString(); 46 | 47 | offset_t target = chunk->getTargetAddr(); 48 | QString str = disasm1.getStringAt(target, chunk->getTargetAddrType()); 49 | if (str.length() > 0) { 50 | std::cout << " : " << str.toStdString(); 51 | } 52 | if (chunk->isBranching()) { 53 | 54 | if (target != INVALID_ADDR) { 55 | std::cout << " -> " 56 | << std::hex << exe->convertAddr(target, chunk->getTargetAddrType(), Executable::VA); 57 | } 58 | if (disasm1.isImportCall(i)) { 59 | std::cout << " ; " << disasm1.getImportName(target, chunk->getTargetAddrType()).toStdString(); 60 | } 61 | std::cout << "\n----"; 62 | } 63 | std::cout << "\n"; 64 | } 65 | } 66 | 67 | offset_t convertHex(const QString &str) 68 | { 69 | offset_t offset = INVALID_ADDR; 70 | bool bStatus = false; 71 | offset = str.toUInt(&bStatus,16); 72 | if (!bStatus) { 73 | return INVALID_ADDR; 74 | } 75 | return offset; 76 | } 77 | 78 | int main(int argc, char *argv[]) 79 | { 80 | QCoreApplication app(argc, argv); 81 | 82 | ExeFactory::init(); 83 | 84 | if (argc < 2) { 85 | std::cout << "Bearparser version: " << BEARPARSER_VERSION << "\n"; 86 | std::cout << "Args: \n"; 87 | return 0; 88 | } 89 | 90 | int status = 0; 91 | QString fName = QString(argv[1]); 92 | offset_t offset = INVALID_ADDR; 93 | if (argc >= 2) { 94 | offset = convertHex(QString(argv[2])); 95 | } 96 | try { 97 | FileView* fileView = tryLoading(fName); 98 | if (!fileView) return -1; 99 | 100 | ExeFactory::exe_type exeType = ExeFactory::findMatching(fileView); 101 | if (exeType == ExeFactory::NONE) { 102 | std::cerr << "Type not supported\n"; 103 | ExeFactory::destroy(); 104 | return 1; 105 | } 106 | 107 | std::cout << "Type: " << ExeFactory::getTypeName(exeType).toStdString() << std::endl; 108 | bufsize_t readableSize = fileView->getContentSize(); 109 | bufsize_t allocSize = (readableSize < MINBUF) ? MINBUF : readableSize; 110 | 111 | //std::cout << "Buffering..." << std::endl; 112 | ByteBuffer *buf = new ByteBuffer(fileView, 0, allocSize); 113 | delete fileView; 114 | 115 | //std::cout << "Parsing executable..." << std::endl; 116 | Executable *exe = ExeFactory::build(buf, exeType); 117 | offset_t func_raw_addr = exe->convertAddr(offset, Executable::RVA, Executable::RAW); 118 | if (func_raw_addr == INVALID_ADDR) { 119 | func_raw_addr = exe->getEntryPoint(Executable::RAW); 120 | } 121 | PEFile *pe = dynamic_cast(exe); 122 | if (pe) { 123 | disasmPeFile(pe, func_raw_addr); 124 | } 125 | 126 | delete exe; 127 | delete buf; 128 | 129 | std::cout << "Bye!" << std::endl; 130 | 131 | } catch (CustomException &e) { 132 | std::cerr << "[ERROR] " << e.what() << std::endl; 133 | status = -1; 134 | } 135 | ExeFactory::destroy(); 136 | return status; 137 | } 138 | -------------------------------------------------------------------------------- /disasm-cli/main.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasherezade/beardisasm/18c10d6c82e6b226c54f53c46c4ff1e889c96964/disasm-cli/main.h -------------------------------------------------------------------------------- /disasm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project (mini_disasm) 3 | 4 | message (STATUS "parser_dir='${PARSER_DIR}'") 5 | message (STATUS "parser_lib='${PARSER_LIB}'") 6 | 7 | message(STATUS "udis_dir='${UDIS86_DIR}'") 8 | message(STATUS "udis_lib='${UDIS86_LIB}'") 9 | 10 | message(STATUS "capstone_includes='${CAPSTONE_INC}'") 11 | message(STATUS "capstone_lib='${CAPSTONE_LIB}'") 12 | 13 | if(USE_QT4) 14 | add_compile_definitions(WITH_QT4) 15 | find_package (Qt4 REQUIRED) 16 | include_directories( ${QT_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR} ) 17 | INCLUDE( ${QT_USE_FILE} ) 18 | ADD_DEFINITIONS( ${QT_DEFINITIONS} ) 19 | else() 20 | add_compile_definitions(WITH_QT5) 21 | find_package(Qt5Core REQUIRED) 22 | get_target_property(QtCore_location Qt5::Core LOCATION) 23 | endif() 24 | 25 | include_directories (${PARSER_INC} ${UDIS86_DIR} ${CAPSTONE_INC}) 26 | 27 | include_directories ( 28 | include 29 | ) 30 | 31 | set (hdrs 32 | include/beardisasm.h 33 | include/AddrConverter.h 34 | include/MnemType.h 35 | include/Context.h 36 | include/TargetValue.h 37 | include/DisasmChunk.h 38 | include/DisasmChunkBuf.h 39 | include/CodeBlock.h 40 | include/FuncNameManager.h 41 | include/DisasmBase.h 42 | include/Tracer.h 43 | ExeDisasm.h 44 | Util.h 45 | ) 46 | 47 | if (VIDI_USE_UDIS86) 48 | set (ud_hdrs 49 | udis/UdisChunk.h 50 | udis/UDisasm.h 51 | udis/ExeDisasm.h 52 | ) 53 | set (ud_srcs 54 | udis/UdisChunk.cpp 55 | udis/UDisasm.cpp 56 | ) 57 | endif () 58 | 59 | 60 | set (cd_hdrs 61 | cdis/CapstoneChunk.h 62 | cdis/CDisasm.h 63 | cdis/ExeDisasm.h 64 | ) 65 | 66 | set (srcs 67 | Context.cpp 68 | CodeBlock.cpp 69 | FuncNameManager.cpp 70 | DisasmBase.cpp 71 | DisasmChunk.cpp 72 | DisasmChunkBuf.cpp 73 | Tracer.cpp 74 | Util.cpp 75 | ) 76 | 77 | set (cd_srcs 78 | cdis/CapstoneChunk.cpp 79 | cdis/CDisasm.cpp 80 | ) 81 | 82 | set (pe_hdrs 83 | include/pe/PeDataFetcher.h 84 | include/pe/PeDisasm.h 85 | include/pe/PeTracer.h 86 | ) 87 | 88 | set (pe_srcs 89 | pe/PeDisasm.cpp 90 | pe/PeTracer.cpp 91 | ) 92 | 93 | set (dos_hdrs 94 | include/dos/DosDisasm.h 95 | include/dos/DosTracer.h 96 | ) 97 | 98 | set (dos_srcs 99 | dos/DosDisasm.cpp 100 | dos/DosTracer.cpp 101 | ) 102 | 103 | SOURCE_GROUP("Source Files\\Auto Generated" FILES ${hdrs_moc} ${rcc_src} ) 104 | 105 | SOURCE_GROUP("Source Files\\pe" FILES ${pe_srcs} ) 106 | SOURCE_GROUP("Header Files\\pe" FILES ${pe_hdrs} ) 107 | 108 | SOURCE_GROUP("Source Files\\dos" FILES ${dos_srcs} ) 109 | SOURCE_GROUP("Header Files\\dos" FILES ${dos_hdrs} ) 110 | 111 | if (VIDI_USE_UDIS86) 112 | SOURCE_GROUP("Source Files\\udis" FILES ${ud_srcs} ) 113 | SOURCE_GROUP("Header Files\\udis" FILES ${ud_hdrs} ) 114 | else() 115 | SOURCE_GROUP("Source Files\\cdis" FILES ${cd_srcs} ) 116 | SOURCE_GROUP("Header Files\\cdis" FILES ${cd_hdrs} ) 117 | endif () 118 | 119 | add_library (mini_disasm STATIC ${hdrs_moc} ${hdrs} ${srcs} ${pe_hdrs} ${pe_srcs} ${dos_hdrs} ${dos_srcs} ${ud_hdrs} ${ud_srcs} ${cd_hdrs} ${cd_srcs}) 120 | 121 | if (VIDI_USE_UDIS86) 122 | target_link_libraries (mini_disasm ${PARSER_LIB} ${UDIS86_LIB} ) 123 | else() 124 | target_link_libraries (mini_disasm ${PARSER_LIB} ${CAPSTONE_LIB} ) 125 | endif() 126 | 127 | if(USE_QT4) 128 | qt4_wrap_cpp(hdrs_moc ${hdrs} ${pe_hdrs} ${dllparse_hdrs}) 129 | target_link_libraries ( ${PROJECT_NAME} ${QT_QTCORE_LIBRARIES} ) 130 | else() 131 | qt5_wrap_cpp(hdrs_moc ${hdrs} ${pe_hdrs} ${dllparse_hdrs}) 132 | target_link_libraries( ${PROJECT_NAME} Qt5::Core) 133 | endif() 134 | 135 | 136 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) 137 | 138 | # defines setting: 139 | if (VIDI_USE_UDIS86) 140 | set (def 141 | "BUILD_WITH_UDIS86" 142 | "USE_UDIS86" 143 | ) 144 | list(APPEND deflist ${def}) 145 | set_target_properties(mini_disasm PROPERTIES COMPILE_DEFINITIONS "${deflist}") 146 | endif() 147 | 148 | # dependencies 149 | if (VIDI_USE_UDIS86) 150 | add_dependencies(${PROJECT_NAME} bearparser libudis86 ) 151 | else() 152 | add_dependencies(${PROJECT_NAME} bearparser capstone ) 153 | endif() 154 | 155 | 156 | -------------------------------------------------------------------------------- /disasm/CodeBlock.cpp: -------------------------------------------------------------------------------- 1 | #include "CodeBlock.h" 2 | 3 | using namespace minidis; 4 | 5 | -------------------------------------------------------------------------------- /disasm/Context.cpp: -------------------------------------------------------------------------------- 1 | #include "Context.h" 2 | 3 | void minidis::resetCond(cond_buf &buf) 4 | { 5 | buf.CF = FLAG_UNK; 6 | buf.PF = FLAG_UNK; 7 | buf.AF = FLAG_UNK; 8 | buf.ZF = FLAG_UNK; 9 | buf.SF = FLAG_UNK; 10 | buf.IF = FLAG_UNK; 11 | buf.DF = FLAG_UNK; 12 | buf.OF = FLAG_UNK; 13 | buf.cx = FLAG_UNK; 14 | buf.affectedCounter = 0; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /disasm/DisasmBase.cpp: -------------------------------------------------------------------------------- 1 | #include "DisasmBase.h" 2 | 3 | using namespace minidis; 4 | 5 | const size_t DisasmBase::MAX_ARG_NUM = 2; 6 | 7 | bool DisasmBase::isBlockRet(const mnem_type &mType) 8 | { 9 | switch (mType) { 10 | case MT_RET: 11 | case MT_INT3: 12 | case MT_INVALID: 13 | return true; 14 | } 15 | return false; 16 | } 17 | 18 | bool DisasmBase::isJump(const mnem_type &mType) 19 | { 20 | switch (mType) { 21 | case MT_JUMP: 22 | case MT_COND_JUMP: 23 | return true; 24 | } 25 | return false; 26 | } 27 | 28 | bool DisasmBase::isConditionalBranching(const mnem_type &mType) 29 | { 30 | switch (mType) { 31 | case MT_COND_JUMP: 32 | case MT_LOOP: 33 | return true; 34 | } 35 | return false; 36 | } 37 | 38 | bool DisasmBase::isUnconditionalBranching(const mnem_type &mType) 39 | { 40 | switch (mType) { 41 | case MT_JUMP: 42 | case MT_CALL: 43 | return true; 44 | } 45 | return false; 46 | } 47 | 48 | bool DisasmBase::isBranching(const mnem_type &mType) 49 | { 50 | if (isJump(mType)) { 51 | return true; 52 | } 53 | switch (mType) { 54 | case MT_CALL: 55 | case MT_LOOP: 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | bool DisasmBase::isBlockEnd(const mnem_type &mType) 62 | { 63 | if (isJump(mType)) { 64 | return true; 65 | } 66 | if (isBlockRet(mType)) { 67 | return true; 68 | } 69 | return false; 70 | } 71 | 72 | bool DisasmBase::isImportCall(offset_t offset, Executable::addr_type inType) 73 | { 74 | offset = this->convertAddr(offset, inType, Executable::RAW); 75 | size_t index = this->m_disasmBuf.offsetToIndex(offset); 76 | if (index == INVALID_INDEX) return false; 77 | 78 | return isImportCall(index); 79 | } 80 | 81 | bool DisasmBase::isInternalCall(offset_t offset, Executable::addr_type inType) 82 | { 83 | size_t index = offsetToIndex(offset, inType); 84 | 85 | if (index == INVALID_INDEX) return false; 86 | if (!this->isFollowable(index) ) return false; 87 | 88 | minidis::mnem_type mType = this->getMnemTypeAtIndex(index); 89 | 90 | if (mType != MT_CALL) return false; 91 | if (isImportCall(offset, inType)) return false; 92 | return true; 93 | } 94 | 95 | bool DisasmBase::isOpToRet(const int index, const mnem_type op) const 96 | { 97 | DisasmChunk *dChunk = this->getChunkAtIndex(index); 98 | if (!dChunk || dChunk->getMnemType() != op) return false; 99 | 100 | //is pointer to RET? 101 | offset_t raw = getTargetOffset(index, Executable::RAW); 102 | if (raw == INVALID_ADDR) { 103 | return false; 104 | } 105 | BYTE *cntnt = m_Exe->getContentAt(raw, Executable::RAW, sizeof(OP_RET)); 106 | if (cntnt != NULL && (*cntnt) == OP_RET) { 107 | return true; 108 | } 109 | return false; 110 | } 111 | 112 | bool DisasmBase::isCallToRet(const size_t index) const 113 | { 114 | return isOpToRet(index, MT_CALL); 115 | } 116 | 117 | bool DisasmBase::isPushRet(int index) const 118 | { 119 | DisasmChunk *dChunk = this->getChunkAtIndex(index); 120 | if (!dChunk || dChunk->getMnemType() != MT_PUSH) return false; 121 | 122 | offset_t nRaw = this->getNextOffset(index); 123 | BYTE *cntnt = m_Exe->getContentAt(nRaw, Executable::RAW, sizeof(OP_RET)); 124 | if (cntnt != NULL && (*cntnt) == OP_RET) { 125 | return true; 126 | } 127 | return false; 128 | } 129 | 130 | bool DisasmBase::isInterruptX(size_t index) 131 | { 132 | return (getMnemTypeAtIndex(index) == MT_INTX); 133 | } 134 | 135 | QString DisasmBase::getStringAt(Executable *exe, offset_t target, Executable::addr_type aType) 136 | { 137 | offset_t raw_target = exe->convertAddr(target, aType, Executable::RAW); 138 | QString str = exe->getStringValue(raw_target); 139 | if (str.size() == 1) { 140 | str = exe->getWAsciiStringValue(raw_target, 100); 141 | } 142 | if (str.trimmed().length() == 0) return ""; 143 | return str; 144 | } 145 | 146 | offset_t DisasmBase::getImmediate(offset_t lval, Executable::addr_type outType, Executable::addr_type hintType) const 147 | { 148 | offset_t val = DisasmBase::trimToBitMode(lval, m_bitMode); 149 | Executable::addr_type detectedType = this->detectAddrType(val, hintType); 150 | //strict type check: 151 | if (detectedType != hintType) { 152 | return INVALID_ADDR; 153 | } 154 | return convertAddr(val, detectedType, outType); 155 | } 156 | 157 | uint64_t DisasmBase::trimToBitMode(int64_t value, Executable::exe_bits bits) 158 | { 159 | uint64_t lval = value; 160 | size_t max_bits = sizeof(lval) * 8; 161 | size_t dif = max_bits - bits; 162 | lval = (lval << dif) >> dif; 163 | return lval; 164 | } 165 | 166 | int32_t DisasmBase::getTargetDelta(const size_t index) const 167 | { 168 | offset_t rva = getTargetOffset(index, Executable::RVA); 169 | if (rva == INVALID_ADDR) return 0; 170 | 171 | offset_t currRVA = getOffset(index, Executable::RVA); 172 | int32_t delta = static_cast(rva - currRVA); 173 | return delta; 174 | } 175 | 176 | bool DisasmBase::isFollowable(const size_t index) const 177 | { 178 | DisasmChunk *uChunk = m_disasmBuf.at(index); 179 | if (!uChunk) return false; 180 | 181 | if (uChunk->isBranching() == false && isPushRet(index) == false) { 182 | return false; 183 | } 184 | offset_t targetRVA = getTargetOffset(index, Executable::RVA); 185 | if (targetRVA == INVALID_ADDR) { 186 | return false; 187 | } 188 | if (this->isImportedFunction(targetRVA, Executable::RVA)) { 189 | return false; 190 | } 191 | return true; 192 | } 193 | 194 | target_state DisasmBase::getTargetState(const size_t index) const 195 | { 196 | //TODO: set this value during parsing target! 197 | const offset_t targetRaw = getTargetOffset(index, Executable::RAW); 198 | const offset_t targetRVA = getTargetOffset(index, Executable::RVA); 199 | 200 | if (targetRaw == INVALID_ADDR && targetRVA == INVALID_ADDR) { 201 | //target does not exist 202 | return TS_NOT_ADDR; 203 | } 204 | if (targetRaw != INVALID_ADDR) { 205 | return TS_VALID; 206 | } 207 | return TS_VIRTUAL_ONLY; 208 | } 209 | 210 | offset_t DisasmBase::getTargetOffset(const size_t index, Executable::addr_type aType) const 211 | { 212 | if (index >= this->m_disasmBuf.size()) return INVALID_ADDR; 213 | DisasmChunk *uChunk = this->m_disasmBuf.at(index); 214 | if (!uChunk) return INVALID_ADDR; 215 | 216 | if (aType == Executable::RAW) { 217 | return uChunk->getTargetRaw(); 218 | } 219 | return convertAddr(uChunk->getTargetAddr(), uChunk->getTargetAddrType(), aType); 220 | } 221 | 222 | bool DisasmBase::fillTable(const DisasmSettings &settings) 223 | { 224 | if (this->is_init == false) { 225 | printf("Not initialized!\n"); 226 | return false; 227 | } 228 | 229 | const size_t maxElements = settings.getMaxDisasmElements(); 230 | bool stopAtBlockEnd = settings.isStopAtBlockEnd(); 231 | bool stopAtFuncEnd = settings.isStopAtFuncEnd(); 232 | 233 | size_t index = 0; 234 | offset_t startRVA = this->convertAddr(m_startOffset, Executable::RAW, Executable::RVA); 235 | for (index = 0; disasmNext() > 0; index ++) { 236 | 237 | DisasmChunk *uChunk = makeChunk(startRVA); 238 | if (!uChunk) break; 239 | 240 | m_disasmBuf.append(uChunk); 241 | //if (index < 2) printf("+%s\n", uChunk->toString().toStdString().c_str()); 242 | if (m_disasmBuf.size() == maxElements) { 243 | stopAtFuncEnd = true; 244 | } 245 | if (m_disasmBuf.indexToOffset(index) == INVALID_ADDR) { 246 | break; 247 | } 248 | if (stopAtFuncEnd) { 249 | if (uChunk->isFuncEnd()) { 250 | //it is a block end, but not a branching 251 | break; 252 | } 253 | } 254 | if (stopAtBlockEnd) { 255 | if (uChunk->isFuncEnd() || uChunk->isBranching()) { 256 | //printf("+%s\n", uChunk->toString().toStdString().c_str()); 257 | break; 258 | } 259 | } 260 | } 261 | return true; 262 | } -------------------------------------------------------------------------------- /disasm/DisasmChunk.cpp: -------------------------------------------------------------------------------- 1 | #include "DisasmChunk.h" 2 | 3 | using namespace minidis; 4 | 5 | const size_t DisasmChunk::MAX_ARG_NUM = 2; 6 | 7 | uint64_t trimToBitMode(int64_t value, Executable::exe_bits bits) 8 | { 9 | uint64_t lval = value; 10 | size_t max_bits = sizeof(lval) * 8; 11 | size_t dif = max_bits - bits; 12 | lval = (lval << dif) >> dif; 13 | return lval; 14 | } 15 | 16 | offset_t DisasmChunk::getImmediate(offset_t lval, Executable::addr_type outType, Executable::addr_type hintType) const 17 | { 18 | offset_t val = trimToBitMode(lval, m_bitMode); 19 | Executable::addr_type detectedType = this->detectAddrType(val, hintType); 20 | if (detectedType != hintType) return INVALID_ADDR; 21 | 22 | return convertAddr(val, detectedType, outType); 23 | } 24 | 25 | bool DisasmChunk::isFuncEnd() const 26 | { 27 | mnem_type mnem = getMnemType(); 28 | switch (mnem) { 29 | case MT_RET : 30 | case MT_INT3: 31 | case MT_INVALID: 32 | return true; 33 | } 34 | return false; 35 | } 36 | 37 | bool DisasmChunk::isRet() const 38 | { 39 | mnem_type mnem = getMnemType(); 40 | if (mnem == MT_RET) { 41 | return true; 42 | } 43 | return false; 44 | } 45 | 46 | /* 47 | TargetValue DisasmChunk::fetchTargetAddr() 48 | { 49 | TargetValue targetVal; 50 | targetVal.setValues(0, Executable::NOT_ADDR, INVALID_ADDR, INVALID_ADDR); 51 | 52 | const size_t cnt = getMaxArg(); 53 | if (cnt == 0) return targetVal; 54 | 55 | for (size_t i = 0; i < cnt; i++) { 56 | 57 | bool isOk = fetchTargetAddr(i, targetVal); 58 | if (!isOk || targetVal.getAddrType() == Executable::NOT_ADDR) continue; 59 | // OK: 60 | return targetVal; 61 | } 62 | targetVal.setValues(0, Executable::NOT_ADDR, INVALID_ADDR, INVALID_ADDR); 63 | return targetVal; 64 | } 65 | */ 66 | bool DisasmChunk::isBranching() const 67 | { 68 | return isConditionalBranching() || isUnconditionalBranching(); 69 | } 70 | 71 | bool DisasmChunk::isConditionalBranching() const 72 | { 73 | switch (m_mnemType) { 74 | case MT_COND_JUMP: 75 | case MT_LOOP: 76 | return true; 77 | } 78 | return false; 79 | } 80 | 81 | bool DisasmChunk::isUnconditionalBranching() const 82 | { 83 | switch (m_mnemType) { 84 | case MT_JUMP: 85 | case MT_CALL: 86 | return true; 87 | } 88 | return false; 89 | } 90 | 91 | bool DisasmChunk::isJump() const 92 | { 93 | switch (m_mnemType) { 94 | case MT_JUMP: 95 | case MT_COND_JUMP: 96 | return true; 97 | } 98 | return false; 99 | } 100 | -------------------------------------------------------------------------------- /disasm/DisasmChunkBuf.cpp: -------------------------------------------------------------------------------- 1 | #include "DisasmChunkBuf.h" 2 | 3 | using namespace minidis; 4 | 5 | void DisasmChunkBuf::append(DisasmChunk* chunk) 6 | { 7 | if (!chunk) return; 8 | 9 | const size_t index = m_table.size(); 10 | const offset_t offset = chunk->getOffset(); 11 | 12 | m_table.push_back(chunk); 13 | m_offsetToIndex[offset] = index; 14 | } 15 | 16 | offset_t DisasmChunkBuf::indexToOffset(const size_t index) const 17 | { 18 | DisasmChunk* chunk = at(index); 19 | if (!chunk) { 20 | return INVALID_ADDR; 21 | } 22 | offset_t offset = chunk->getOffset(); 23 | //printf("offset = %x m_offset: %x\n", offset, m_offset); 24 | offset += m_offset; 25 | return offset; 26 | } 27 | 28 | size_t DisasmChunkBuf::offsetToIndex(const offset_t raw) const 29 | { 30 | if (raw < m_offset) { 31 | return INVALID_INDEX; 32 | } 33 | offset_t offset = raw - m_offset; 34 | std::map::const_iterator itr = m_offsetToIndex.find(offset); 35 | if (itr == m_offsetToIndex.end()) { 36 | return INVALID_INDEX; 37 | } 38 | size_t index = itr->second; 39 | return index; 40 | } 41 | 42 | QString DisasmChunkBuf::getDisasmString(const size_t index) 43 | { 44 | DisasmChunk* chunk = at(index); 45 | if (!chunk) return ""; 46 | 47 | return chunk->toString(); 48 | } 49 | 50 | bufsize_t DisasmChunkBuf::getChunkSize(const size_t index) const 51 | { 52 | DisasmChunk* chunk = at(index); 53 | if (!chunk) return 0; 54 | 55 | return chunk->getChunkSize(); 56 | } 57 | -------------------------------------------------------------------------------- /disasm/ExeDisasm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef BUILD_WITH_UDIS86 4 | #include "cdis/ExeDisasm.h" 5 | #else 6 | #ifdef USE_UDIS86 7 | #include "udis/ExeDisasm.h" 8 | #else 9 | #include "cdis/ExeDisasm.h" 10 | #endif 11 | #endif 12 | -------------------------------------------------------------------------------- /disasm/FuncNameManager.cpp: -------------------------------------------------------------------------------- 1 | #include "FuncNameManager.h" 2 | #include "Tracer.h" 3 | 4 | using namespace minidis; 5 | 6 | bool FuncNameManager::setFunctionName(offset_t offset, Executable::addr_type inType, QString name) 7 | { 8 | offset = m_Converter->convertAddr(offset, inType, Executable::RAW); 9 | if (offset == INVALID_ADDR) return false; 10 | 11 | bool tagExist = false; 12 | if (this->functionToName.contains(offset)) { 13 | nameToFunction.remove(functionToName[offset]); 14 | tagExist = true; 15 | } 16 | if (name == "") { 17 | this->functionToName.remove(offset); 18 | m_namedOffsetsList.removeOne(offset); 19 | return true; 20 | } 21 | if (nameToFunction.contains(name)) { 22 | name = name + "@" + QString::number(offset, 16); 23 | } 24 | functionToName[offset] = name; 25 | nameToFunction[name] = offset; 26 | if (!tagExist) m_namedOffsetsList.append(offset); 27 | return true; 28 | } 29 | 30 | bool FuncNameManager::hasName(offset_t offset, Executable::addr_type inType) const 31 | { 32 | offset_t raw = m_Converter->convertAddr(offset, inType, Executable::RAW); 33 | return functionToName.contains(raw); 34 | } 35 | 36 | QString FuncNameManager::getFunctionName(offset_t offset, Executable::addr_type inType) const 37 | { 38 | offset_t raw = m_Converter->convertAddr(offset, inType, Executable::RAW); 39 | if (raw == INVALID_ADDR) { 40 | return " "; 41 | } 42 | if (this->functionToName.contains(raw)) { 43 | return functionToName[raw]; 44 | } 45 | return QString::number(offset, 16); 46 | } 47 | 48 | //---- 49 | 50 | FuncManager::FuncManager(AddrConverter *converter) 51 | : m_Converter(converter), m_aType(Executable::RVA) 52 | { 53 | } 54 | 55 | Executable::addr_type FuncManager::getAddrType() 56 | { 57 | return m_aType; 58 | } 59 | 60 | bool FuncManager::appendFunction(offset_t offset, Executable::addr_type inType) 61 | { 62 | offset_t cOffset = m_Converter->convertAddr(offset, inType, m_aType); 63 | if (cOffset == INVALID_ADDR) { 64 | printf("Cannot append function : failed convertion at : %llx\n", static_cast(offset)); 65 | return false; 66 | } 67 | size_t size = m_functions.size(); 68 | m_functions.insert(cOffset); 69 | 70 | if (m_functions.size() == size) { //already exist 71 | return true; 72 | } 73 | this->m_functionsList.append(cOffset); 74 | return true; 75 | } 76 | 77 | size_t FuncNameManager::save(const QString &fileName) 78 | { 79 | QFile outputFile(fileName); 80 | if ( !outputFile.open(QIODevice::WriteOnly | QIODevice::Text) ) return 0; 81 | 82 | QTextStream out(&outputFile); 83 | QMap::iterator itr; 84 | size_t counter = 0; 85 | for (itr = functionToName.begin(); itr != functionToName.end(); ++itr) { 86 | //convert every offset into RVA: 87 | offset_t rva = m_Converter->convertAddr(itr.key(), Executable::RAW, Executable::RVA); 88 | out << hex << rva; 89 | out << ","; 90 | out << itr.value(); 91 | out << '\n'; 92 | counter++; 93 | 94 | } 95 | outputFile.close(); 96 | return counter; 97 | } 98 | 99 | size_t FuncNameManager::load(const QString &fileName) 100 | { 101 | size_t loaded = 0; 102 | QFile inputFile(fileName); 103 | 104 | if ( !inputFile.open(QIODevice::ReadOnly) ) { 105 | printf("Cannot open file!"); 106 | return 0; 107 | } 108 | offset_t offset = 0; 109 | QString thunkStr = ""; 110 | QString funcName = ""; 111 | 112 | QTextStream in(&inputFile); 113 | while ( !in.atEnd() ) { 114 | QString line = in.readLine(); 115 | QStringList list = line.split(','); 116 | if (list.size() < 2) { 117 | continue; //invalid line, skip it 118 | } 119 | QString thunkStr = list[0]; 120 | QString funcName = list[1]; 121 | bool isOk = false; 122 | offset = thunkStr.toLongLong(&isOk, 16); 123 | 124 | if (!isOk) { 125 | continue; //invalid line, skip it 126 | } 127 | //functions are stored by RVAs 128 | if (setFunctionName(offset, Executable::RVA, funcName)) loaded++; 129 | } 130 | inputFile.close(); 131 | return loaded; 132 | } -------------------------------------------------------------------------------- /disasm/Tracer.cpp: -------------------------------------------------------------------------------- 1 | #include "Tracer.h" 2 | 3 | using namespace minidis; 4 | 5 | #include "ExeDisasm.h" 6 | 7 | bool Tracer::resolveOffset(offset_t offset, Executable::addr_type aType) 8 | { 9 | offset_t raw = this->convertAddr(offset, aType, Executable::RAW); 10 | if (this->getDisasmAt(raw, Executable::RAW)) return true; 11 | 12 | if (!this->makeDisasmAt(m_Exe, raw, this->functionTraceSettings)) { 13 | return false; //FAILED 14 | } 15 | this->traceArea(raw); 16 | return true; 17 | } 18 | 19 | QString Tracer::getStringAt(offset_t target) 20 | { 21 | return DisasmBase::getStringAt(this->m_Exe, target, Executable::RAW); 22 | } 23 | 24 | CodeBlock* Tracer::getOrMakeCodeBlockAt(offset_t offset) 25 | { 26 | if (offset == INVALID_ADDR) return NULL; 27 | 28 | if (!this->getDisasmAt(offset)) { 29 | m_unsolvedOffsets.insert(offset); 30 | //printf("UNSOLVED at = %x\n", offset); 31 | return NULL; 32 | } 33 | if (m_blocks.contains(offset)) { 34 | return &m_blocks[offset]; 35 | } 36 | m_blocks[offset] = CodeBlock(offset); 37 | m_blockPtrs[offset] = &m_blocks[offset]; 38 | //printf("Adding new block at = %x\n", offset); 39 | return &m_blocks[offset]; 40 | } 41 | 42 | size_t Tracer::fetchUnsolved(QSet &unsolved) 43 | { 44 | size_t added = 0; 45 | for (QMap::iterator itr = m_forks.begin();itr != m_forks.end(); ++itr) { 46 | ForkPoint &p = itr.value(); 47 | offset_t uOff = p.yesOffset; 48 | if (uOff == INVALID_ADDR) continue; 49 | if (!getDisasmAt(uOff)) { 50 | unsolved.insert(uOff); 51 | added++; 52 | } 53 | } 54 | QList func = m_funcManager.list(); 55 | for (QList::iterator itr = func.begin();itr != func.end(); ++itr) { 56 | offset_t uOff = *itr; 57 | uOff = this->convertAddr(uOff, m_funcManager.getAddrType(), Executable::RAW); 58 | if (uOff == INVALID_ADDR) continue; 59 | if (!getDisasmAt(uOff)) { 60 | unsolved.insert(uOff); 61 | added++; 62 | } 63 | } 64 | return added; 65 | } 66 | 67 | size_t Tracer::resolveUnsolvedBranches(const QSet &unsolved) 68 | { 69 | size_t added = 0; 70 | QSet::const_iterator oItr; 71 | for (oItr = unsolved.begin();oItr != unsolved.end(); ++oItr) { 72 | offset_t uOff = *oItr; 73 | if (uOff == INVALID_ADDR) continue; 74 | if (!getDisasmAt(uOff)) { 75 | if (this->makeDisasmAt(m_Exe, uOff, this->functionTraceSettings)) { 76 | traceArea(uOff); 77 | added++; 78 | } 79 | } 80 | } 81 | return added; 82 | } 83 | 84 | void Tracer::addReferencedTargets(offset_t currOff, offset_t target, DisasmChunk *chunk) 85 | { 86 | if (chunk == NULL || currOff == INVALID_ADDR || target == INVALID_ADDR) return; 87 | 88 | bool import = this->isImportedFunction(target, Executable::RAW); 89 | if (import) { 90 | if (m_impFuncManager.appendFunction(target, Executable::RAW)) { 91 | addReference(target, currOff); 92 | } 93 | return; 94 | } 95 | const mnem_type mType = chunk->getMnemType(); 96 | if (mType == MT_CALL) { 97 | //local function called 98 | if (m_funcManager.appendFunction(target, Executable::RAW)) { 99 | addReference(target, currOff); 100 | } 101 | return; 102 | } 103 | 104 | if (DisasmBase::isBranching(mType)) return; 105 | if (m_referedStrings.contains(target)) { 106 | addReference(target, currOff); 107 | } else { 108 | QString str = this->getStringAt(target); 109 | if (str.length() > 0) { 110 | m_referedStrings[target] = str; 111 | this->m_referedStringsList.append(target); 112 | addReference(target, currOff); 113 | } 114 | } 115 | } 116 | 117 | bool Tracer::appendCodeChunk(DisasmBase* disasm, CodeBlock* block, const offset_t currOff) 118 | { 119 | if (!disasm || !block || currOff == INVALID_ADDR) return false; 120 | m_disasmPtrs[currOff] = disasm; 121 | 122 | if (!block->append(currOff)) { 123 | //printf("Cannot append to block\n"); 124 | return false; 125 | } 126 | m_blockPtrs[currOff] = block; 127 | return true; 128 | } 129 | 130 | void Tracer::addForkPoint(offset_t currOff, offset_t target, offset_t next) 131 | { 132 | m_forks[currOff] = ForkPoint(currOff, target, next); 133 | addReference(target, currOff); 134 | addReference(next, currOff); 135 | } 136 | 137 | void Tracer::traceBlocks(DisasmBase* disasm, offset_t startOffset) 138 | { 139 | if (!disasm) return; 140 | 141 | const Executable::addr_type aType = Executable::RAW; 142 | 143 | const size_t startIndex = disasm->m_disasmBuf.offsetToIndex(startOffset); 144 | const size_t disasmSize = disasm->m_disasmBuf.size(); 145 | 146 | const size_t initialBlockCount = m_blocks.size(); 147 | 148 | offset_t newOffset = startOffset; 149 | CodeBlock* block = NULL; 150 | 151 | const bool skipExisting = true; 152 | for (size_t index = startIndex; index < disasmSize; index++) 153 | { 154 | if (!block) { 155 | CodeBlock *existingBlock = this->blockStartingAt(newOffset, Executable::RAW); 156 | if (existingBlock) { 157 | if (!skipExisting) { 158 | std::cout <getEndOffset(); 162 | if (endOffset == INVALID_ADDR) break; 163 | 164 | int lastIndx = existingBlock->getIndexOf(endOffset); 165 | if (lastIndx == INVALID_INDEX) break; 166 | newOffset = disasm->getNextOffset(index); 167 | //std::cout << "Skipping to next offset: " << std::hex << newOffset << "\n"; 168 | continue; 169 | } 170 | block = getOrMakeCodeBlockAt(newOffset); 171 | if (!block) break; 172 | //std::cout << "New block: " << std::hex << newOffset << std::endl; 173 | } 174 | DisasmChunk *chunk = disasm->getChunkAtIndex(index); 175 | if (!chunk) break; 176 | 177 | const offset_t currOff = disasm->getOffset(index); 178 | if (currOff == INVALID_ADDR) { 179 | break; 180 | } 181 | mnem_type mType = disasm->getMnemTypeAtIndex(index); 182 | offset_t target = disasm->getTargetOffset(index, Executable::RAW); 183 | offset_t targetRVA = disasm->getTargetOffset(index, Executable::RVA); 184 | 185 | if (!appendCodeChunk(disasm, block, currOff)) { 186 | //printf("Could not append code chunk at: %lx\n", currOff); 187 | break; 188 | } 189 | 190 | if (mType == MT_INVALID) { 191 | block->markInvalid(); 192 | } 193 | 194 | if (target != INVALID_ADDR) { 195 | addReferencedTargets(currOff, target, chunk); 196 | if (disasm->isPushRet(index)) { 197 | //local function called 198 | if (m_funcManager.appendFunction(target, Executable::RAW)) { 199 | addReference(target, currOff); 200 | } 201 | } 202 | } 203 | 204 | if (!disasm->isBlockEnd(mType)) { 205 | //the block is not finished yet, process further chunks 206 | continue; 207 | } 208 | //block finished: 209 | if (disasm->isBranching(index) && target == INVALID_ADDR) { 210 | block->markInvalid(); 211 | } 212 | 213 | if (disasm->isBranching(index) && !block->isInvalid()) { 214 | bool import = this->isImportedFunction(target, Executable::RAW); 215 | 216 | if (disasm->isConditionalBranching(mType)) { 217 | const offset_t next = disasm->getNextOffset(index); 218 | addForkPoint(currOff, target, next); 219 | 220 | } else if (!isImportedFunction(target, Executable::RAW)) { 221 | //add jump fork point only if it is not a jump to import 222 | addForkPoint(currOff, target, INVALID_ADDR); 223 | } 224 | } 225 | if (block->size == 0) { 226 | if (mType == MT_INT3) block->markInvalid(); 227 | } 228 | newOffset = disasm->getNextOffset(index); 229 | //reset block: 230 | block = NULL; 231 | } 232 | 233 | if (initialBlockCount == m_blocks.size()){ 234 | std::cout << "No blocks added!\n"; 235 | return; 236 | } 237 | filterValidBlocks(); 238 | } 239 | 240 | void Tracer::traceArea(offset_t startOffset) 241 | { 242 | if (!m_offsetToDisasm.contains(startOffset)) { 243 | return; 244 | } 245 | DisasmBase* disasm = this->getDisasmAt(startOffset); 246 | if (!disasm) return; 247 | //printf("Got disasm at startOffset = %lx ,ptr =%x\n", startOffset, disasm); 248 | traceBlocks(disasm, startOffset); 249 | traceReferencedCodeBlocks(); 250 | } 251 | 252 | void Tracer::filterValidBlocks() 253 | { 254 | //block addr type: RAW 255 | QMap::iterator itr; 256 | for (itr = this->m_blocks.begin(); itr != m_blocks.end(); ++itr) { 257 | 258 | offset_t offset = itr.key(); 259 | CodeBlock &block = itr.value(); 260 | int size = m_validBlocksOffsetsSet.size(); 261 | 262 | if (!block.isInvalid()) { // valid 263 | m_validBlocksOffsetsSet.insert(offset); 264 | } 265 | // if offset is new, append it! 266 | if (size < m_validBlocksOffsetsSet.size()) { 267 | this->m_validBlocksOffsets.append(offset); 268 | } 269 | } 270 | } 271 | 272 | void Tracer::traceReferencedCodeBlocks() 273 | { 274 | QMap >::iterator itr; 275 | for (itr = this->m_refs.begin(); itr != m_refs.end(); ++itr ) { 276 | offset_t offset = itr.key(); 277 | QSet &rSet = itr.value(); 278 | QSet::iterator itrR; 279 | 280 | for (itrR = rSet.begin(); itrR != rSet.end(); ++itrR ) { 281 | CodeBlock* block = this->blockAt(*itrR); 282 | if (!block) continue; 283 | this->m_refBlocks[offset].insert(block); 284 | } 285 | } 286 | } 287 | 288 | DisasmBase* Tracer::getDisasmAt(offset_t offset, Executable::addr_type inType) const 289 | { 290 | offset = this->convertAddr(offset, inType, Executable::RAW); 291 | if (m_offsetToDisasm.contains(offset)) { 292 | return m_offsetToDisasm[offset]; 293 | } 294 | if (m_disasmPtrs.contains(offset)) { 295 | return m_disasmPtrs[offset]; 296 | } 297 | // closest 298 | QMap::const_iterator disItr = this->m_offsetToDisasm.begin();//upperBound(offset); 299 | for (; disItr != this->m_offsetToDisasm.constEnd(); ++disItr) { 300 | DisasmBase* dis = disItr.value(); 301 | if (dis->hasOffset(offset)) { 302 | return dis; 303 | } 304 | } 305 | return NULL; 306 | } 307 | 308 | bool Tracer::makeDisasmAt(Executable* exe, offset_t offset, DisasmSettings &settings) 309 | { 310 | //printf("Disasm making at %x\n", offset); 311 | DisasmBase *disasm = getDisasmAt(offset); 312 | if (!disasm) { 313 | disasm = makeDisasm(exe, offset); 314 | if (!disasm) return false; 315 | m_offsetToDisasm[offset] = disasm; 316 | } 317 | disasm = m_offsetToDisasm[offset]; 318 | //printf("Filling table...\n"); 319 | disasm->fillTable(settings); 320 | return true; 321 | } 322 | 323 | bool Tracer::isInternalCall(offset_t offset, Executable::addr_type inType) 324 | { 325 | offset = this->convertAddr(offset, inType, Executable::RAW); 326 | DisasmBase* dis = getDisasmAt(offset); 327 | if (!dis) return NULL; 328 | 329 | size_t index = dis->m_disasmBuf.offsetToIndex(offset); 330 | if (index == INVALID_INDEX) return false; 331 | 332 | if (!dis->isFollowable(index) ) return false; 333 | 334 | mnem_type mnem = dis->getMnemTypeAtIndex(index); 335 | if ((mnem == MT_CALL && !dis->isCallToRet(index)) || dis->isPushRet(index)) { 336 | if (dis->isImportCall(offset, inType)) return false; 337 | return true; 338 | } 339 | return false; 340 | } 341 | 342 | bool Tracer::defineFunction(offset_t offset, Executable::addr_type aType, QString name) 343 | { 344 | const offset_t start = this->convertAddr(offset, aType, Executable::RAW); 345 | if (start == INVALID_ADDR) return false; 346 | 347 | this->m_funcManager.appendFunction(start, Executable::RAW); 348 | if (name.length() > 0) { 349 | this->m_nameManager.setFunctionName(start, Executable::RAW, name); 350 | } 351 | return true; 352 | } 353 | 354 | QString Tracer::translateBranching(DisasmBase* dis, const size_t index, FuncNameManager *nameManager) const 355 | { 356 | if (!dis) return ""; 357 | DisasmChunk *uChunk = dis->m_disasmBuf.at(index); 358 | if (!uChunk) return ""; 359 | 360 | const Executable::addr_type targetAddrType = uChunk->getTargetAddrType(); 361 | if (targetAddrType == Executable::NOT_ADDR) { 362 | return uChunk->toString(); 363 | } 364 | 365 | const offset_t targetOrig = dis->getTargetOffset(index, targetAddrType); 366 | const offset_t targetRVA = this->convertAddr(targetOrig, targetAddrType, Executable::RVA); 367 | const offset_t targetRaw = this->convertAddr(targetOrig, targetAddrType, Executable::RAW); 368 | 369 | if (uChunk->isTargetImm() && uChunk->isBranching()) { 370 | return uChunk->translateBranchingMnemonic() + " " + nameManager->getFunctionName(targetOrig, targetAddrType); 371 | } 372 | 373 | QString mnemDesc = uChunk->toString(); 374 | 375 | if (targetRaw == INVALID_ADDR) { 376 | return mnemDesc;// + " "; 377 | } 378 | if (!nameManager) return mnemDesc; 379 | 380 | bool isNamed = nameManager->hasName(targetRVA, Executable::RVA); 381 | if (isNamed) { 382 | return mnemDesc + " " + nameManager->getFunctionName(targetRVA, Executable::RVA); 383 | } 384 | return mnemDesc; 385 | } 386 | -------------------------------------------------------------------------------- /disasm/Util.cpp: -------------------------------------------------------------------------------- 1 | #include "Util.h" 2 | 3 | BYTE* find_pattern(BYTE *buffer, size_t buf_size, BYTE* pattern_buf, size_t pattern_size, size_t max_iter) 4 | { 5 | for (size_t i = 0; (i + pattern_size) < buf_size; i++) { 6 | if (max_iter != 0 && i > max_iter) break; 7 | if (memcmp(buffer + i, pattern_buf, pattern_size) == 0) { 8 | return (buffer + i); 9 | } 10 | } 11 | return NULL; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /disasm/Util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | BYTE* find_pattern(BYTE *buffer, size_t buf_size, BYTE* pattern_buf, size_t pattern_size, size_t max_iter = 0); 6 | -------------------------------------------------------------------------------- /disasm/cdis/CDisasm.cpp: -------------------------------------------------------------------------------- 1 | #include "CDisasm.h" 2 | 3 | using namespace minidis; 4 | 5 | cs_mode toCSmode(Executable::exe_bits bitMode) 6 | { 7 | switch (bitMode) { 8 | case Executable::BITS_16: 9 | return CS_MODE_16; 10 | case Executable::BITS_32: 11 | return CS_MODE_32; 12 | case Executable::BITS_64: 13 | return CS_MODE_64; 14 | } 15 | return CS_MODE_32; //Default 16 | } 17 | 18 | bool CDisasm::init_capstone(Executable::exe_bits bitMode) 19 | { 20 | cs_err err; 21 | err = cs_open(CS_ARCH_X86, toCSmode(bitMode), &handle); 22 | if (err) { 23 | printf("Failed on cs_open() with error returned: %u\n", err); 24 | return false; 25 | } 26 | cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); 27 | cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); 28 | m_insn = cs_malloc(handle); 29 | if (!m_insn) { 30 | cs_close(&handle); 31 | return false; 32 | } 33 | return true; 34 | } 35 | 36 | size_t CDisasm::capstone_next(const BYTE *code, size_t size, offset_t startRaw) 37 | { 38 | bool isOk = cs_disasm_iter(handle, &code, &size, &startRaw, m_insn); 39 | //m_csCount = cs_disasm(handle, code, size, startRaw, 1, &insn); 40 | if (!isOk || !m_insn) { 41 | return 0; 42 | } 43 | //printf("Disasembled: %d\t %s %s\t%lx\n", m_csCount, insn[0].mnemonic, insn[0].op_str, insn[0].address); 44 | return m_insn->size; 45 | } 46 | 47 | bool CDisasm::init(const offset_t raw, const bufsize_t disasmSize, Executable::exe_bits bitMode) 48 | { 49 | m_startOffset = raw; 50 | m_bitMode = bitMode; 51 | m_disasmBuf.clear(); 52 | 53 | //printf("CDisasm::init : Init buffer at offset %lx bit mode: %d\n", m_startOffset, m_bitMode); 54 | m_buf = m_Exe->getContentAt(m_startOffset, Executable::RAW); 55 | m_bufSize = m_Exe->getContentSize() - m_startOffset; 56 | 57 | if (m_buf == NULL || m_bufSize == 0) return false; 58 | 59 | m_disasmSize = m_bufSize < disasmSize ? m_bufSize : disasmSize; 60 | m_disasmBuf.setStartOffset(m_startOffset); 61 | 62 | m_csBuf = m_buf; 63 | m_csBufSize = m_disasmSize; 64 | m_csOffset = 0; 65 | 66 | this->is_init = init_capstone(m_bitMode); 67 | return this->is_init; 68 | } 69 | 70 | size_t CDisasm::disasmNext() 71 | { 72 | if (!is_init && m_insn) { 73 | printf("Cannot disasm next = NOT INIT!\n"); 74 | return 0; 75 | } 76 | //bool cs_disasm_iter(csh ud, const uint8_t **code, size_t *size, 77 | size_t step = capstone_next(m_csBuf, m_csBufSize, m_csOffset); 78 | if (step == 0) { 79 | is_init = false; 80 | return 0; 81 | } 82 | m_csBuf += step; 83 | m_csBufSize -= step; 84 | m_csOffset += step; 85 | return step; 86 | } 87 | 88 | DisasmChunk* CDisasm::makeChunk(offset_t startRVA) 89 | { 90 | if (!m_insn) { 91 | return NULL; 92 | } 93 | return new CapstoneChunk(*m_insn, startRVA, m_Exe); 94 | } 95 | -------------------------------------------------------------------------------- /disasm/cdis/CDisasm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "DisasmBase.h" 5 | 6 | #include "CapstoneChunk.h" 7 | 8 | namespace minidis { 9 | //------------------------------------------------ 10 | /* abstract class, base of all the Disasms*/ 11 | class CDisasm : public DisasmBase 12 | { 13 | public: 14 | 15 | CDisasm(Executable* exe, offset_t startOffset) 16 | : DisasmBase(exe, startOffset), m_insn(NULL) 17 | { 18 | } 19 | 20 | ~CDisasm() 21 | { 22 | if (m_insn){ 23 | cs_free(m_insn, 1); 24 | cs_close(&handle); //TODO: check if ever opened 25 | } 26 | } 27 | 28 | bool init(const offset_t startOffset, const bufsize_t disasmSize, Executable::exe_bits bitMode); 29 | 30 | protected: 31 | virtual DisasmChunk* makeChunk(offset_t startRVA); 32 | virtual size_t disasmNext(); 33 | 34 | bool init_capstone(Executable::exe_bits bitMode); 35 | size_t capstone_next(const BYTE *code, size_t size, offset_t startRaw); 36 | 37 | csh handle; 38 | cs_insn* m_insn; 39 | 40 | BYTE *m_csBuf; 41 | bufsize_t m_csBufSize; 42 | offset_t m_csOffset; 43 | 44 | BYTE *m_buf; 45 | bufsize_t m_bufSize; 46 | bufsize_t m_disasmSize; 47 | 48 | }; /* class DisasmBase */ 49 | 50 | }; /* namespace minidis */ 51 | -------------------------------------------------------------------------------- /disasm/cdis/CapstoneChunk.cpp: -------------------------------------------------------------------------------- 1 | #include "CapstoneChunk.h" 2 | 3 | using namespace minidis; 4 | 5 | #define MAX_ARG_NUM 4 6 | 7 | bool CapstoneChunk::fetchTargetAddr(const size_t argNum, TargetValue &targetVal, cs_detail *m_detail) const 8 | { 9 | if (!m_detail) return false; 10 | 11 | size_t cnt = static_cast(m_detail->x86.op_count); 12 | if (argNum >= cnt) return false; 13 | 14 | targetVal.m_targetOpNum = argNum; 15 | 16 | const size_t opSize = m_detail->x86.operands[argNum].size; 17 | const x86_op_type type = m_detail->x86.operands[argNum].type; 18 | const x86_reg reg = static_cast(m_detail->x86.operands[argNum].mem.base); 19 | 20 | const bool isEIPrelative = (reg == X86_REG_IP || reg == X86_REG_EIP || reg == X86_REG_RIP); 21 | 22 | if (type == X86_OP_MEM) { 23 | 24 | int64_t lval = m_detail->x86.operands[argNum].mem.disp; 25 | 26 | if (reg <= X86_REG_INVALID) { //simple case, no reg value to add 27 | if (!isValidAddr(lval, Executable::VA)) return false; 28 | 29 | return setTargetVal(targetVal, argNum, Executable::VA, lval); 30 | } 31 | if (isEIPrelative) { 32 | const offset_t currIP = this->m_startOffset + this->getOffset() + this->getChunkSize(); 33 | const offset_t target = currIP + lval; 34 | if (!isValidAddr(target, Executable::RVA)) return false; 35 | 36 | return setTargetVal(targetVal, argNum, Executable::RVA, target); 37 | } 38 | } 39 | 40 | if (type == X86_OP_IMM) { 41 | const bool isImm = true; 42 | int64_t lval = this->signExtend(m_detail->x86.operands[argNum].imm, opSize); 43 | 44 | //do not check registers in case of (short) branchings 45 | if (this->isBranching() && !isLongOp()) { 46 | const offset_t target = m_startOffset + lval; 47 | return setTargetVal(targetVal, argNum, Executable::RVA, target, isImm); 48 | } 49 | 50 | if (reg <= X86_REG_INVALID) { //simple case, no reg value to add 51 | if (!isValidAddr(lval, Executable::VA)) return false; 52 | 53 | return setTargetVal(targetVal, argNum, Executable::VA, lval, isImm); 54 | } 55 | //other registers, not supported case 56 | //printf("%s %s\n", this->m_insn.mnemonic, this->m_insn.op_str); 57 | return false; 58 | } 59 | return false; 60 | } 61 | 62 | TargetValue CapstoneChunk::fetchTargetAddr(cs_detail *detail) 63 | { 64 | TargetValue targetVal; 65 | targetVal.setValues(0, Executable::NOT_ADDR, INVALID_ADDR, INVALID_ADDR); 66 | 67 | const size_t cnt = getMaxArg(); 68 | if (cnt == 0) return targetVal; 69 | 70 | for (size_t i = 0; i < cnt; i++) { 71 | 72 | bool isOk = fetchTargetAddr(i, targetVal, detail); 73 | if (!isOk || targetVal.getAddrType() == Executable::NOT_ADDR) continue; 74 | // OK: 75 | return targetVal; 76 | } 77 | targetVal.setValues(0, Executable::NOT_ADDR, INVALID_ADDR, INVALID_ADDR); 78 | return targetVal; 79 | } 80 | //--- 81 | 82 | bool BelongsToGroup(const cs_insn insn, const x86_insn_group group) 83 | { 84 | cs_detail *detail = insn.detail; 85 | if (!detail) return false; 86 | 87 | if (detail->groups_count == 0) { 88 | return false; 89 | } 90 | for (int n = 0; n < detail->groups_count; n++) { 91 | if (detail->groups[n] == group) { 92 | return true; 93 | } 94 | } 95 | return false; 96 | } 97 | 98 | mnem_type CapstoneChunk::fetchMnemType(const cs_insn &insn) 99 | { 100 | const unsigned int cMnem = insn.id; 101 | 102 | if (cMnem == x86_insn::X86_INS_JMP || cMnem == x86_insn::X86_INS_LJMP) { 103 | return MT_JUMP; 104 | } 105 | if (cMnem >= x86_insn::X86_INS_JAE && cMnem <= x86_insn::X86_INS_JS) { 106 | return MT_COND_JUMP; 107 | } 108 | if (cMnem >= X86_INS_MOV && cMnem <= X86_INS_MOVZX) { 109 | return MT_MOV; 110 | } 111 | 112 | switch (cMnem) { 113 | case X86_INS_LOOP: 114 | case X86_INS_LOOPE: 115 | case X86_INS_LOOPNE: 116 | return MT_LOOP; 117 | 118 | case X86_INS_CALL : 119 | case X86_INS_LCALL: 120 | return MT_CALL; 121 | 122 | case X86_INS_RET: 123 | case X86_INS_RETF: 124 | case X86_INS_RETFQ: 125 | return MT_RET; 126 | 127 | case X86_INS_NOP : return MT_NOP; 128 | case X86_INS_INVALID : return MT_INVALID; 129 | 130 | case X86_INS_POP: 131 | case X86_INS_POPAW: 132 | case X86_INS_POPAL: 133 | case X86_INS_POPCNT: 134 | case X86_INS_POPF: 135 | case X86_INS_POPFD: 136 | case X86_INS_POPFQ: 137 | { 138 | return MT_POP; 139 | } 140 | case X86_INS_PUSH: 141 | case X86_INS_PUSHAW: 142 | case X86_INS_PUSHAL: 143 | case X86_INS_PUSHF: 144 | case X86_INS_PUSHFD: 145 | case X86_INS_PUSHFQ: 146 | { 147 | return MT_PUSH; 148 | } 149 | case X86_INS_INT3 : 150 | return MT_INT3; 151 | 152 | case X86_INS_INT: 153 | return MT_INTX; 154 | } 155 | return MT_OTHER; 156 | } 157 | 158 | /* 159 | QString CapstoneChunk::valToString() const 160 | { 161 | if (!m_detail) return ""; 162 | 163 | size_t cnt = static_cast(m_detail->x86.op_count); 164 | if (cnt == 0) return ""; 165 | 166 | QString opCount = " : "+ QString::number(cnt); 167 | if (cnt > 0) { 168 | bool isOk; 169 | int64_t lval = this->getSignedLVal(0, isOk); 170 | if (!isOk) return opCount +" fail"; 171 | 172 | QString opVal = " : "+ QString::number(lval, 16); 173 | return " ("+ opVal +")"; 174 | } 175 | return opCount; 176 | }*/ 177 | 178 | QString CapstoneChunk::translateBranchingMnemonic() const 179 | { 180 | if (this->m_insn.mnemonic == NULL || !this->isBranching()) { 181 | return ""; 182 | } 183 | 184 | QString desc = QString(this->m_insn.mnemonic).toUpper(); 185 | 186 | const x86_insn cMnem = static_cast(this->m_insn.id); 187 | if (cMnem == X86_INS_JMP) { 188 | desc += " SHORT"; 189 | } 190 | return desc; 191 | } 192 | -------------------------------------------------------------------------------- /disasm/cdis/CapstoneChunk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "DisasmChunk.h" 7 | 8 | namespace minidis { 9 | 10 | class CapstoneChunk : public DisasmChunk 11 | { 12 | public: 13 | CapstoneChunk(const cs_insn &insn, offset_t startOffset, Executable *parent) 14 | : DisasmChunk(startOffset, parent), 15 | m_insn(insn) 16 | { 17 | m_maxArgs = insn.detail->x86.op_count; 18 | m_mnemType = fetchMnemType(); 19 | m_targetVal = fetchTargetAddr(insn.detail); 20 | } 21 | 22 | virtual bufsize_t getChunkSize() const{ return this->m_insn.size; } 23 | virtual QString translateBranchingMnemonic() const; 24 | 25 | protected: 26 | virtual void initStrings() 27 | { 28 | m_disasmString = QString(m_insn.mnemonic) + " " + QString(m_insn.op_str);// + " id: " + QString::number(m_insn.id, 10); 29 | m_hexStr = printBytes((uint8_t*) m_insn.bytes, m_insn.size); 30 | } 31 | 32 | virtual size_t getMaxArg() { return m_maxArgs; } 33 | 34 | mnem_type fetchMnemType() const 35 | { 36 | return CapstoneChunk::fetchMnemType(m_insn); 37 | } 38 | 39 | virtual offset_t getOffset() const { return this->m_insn.address; } 40 | bool isLongOp() const { return (this->m_insn.id == X86_INS_LCALL || this->m_insn.id == X86_INS_LJMP); } 41 | 42 | private: 43 | virtual bool fetchTargetAddr(const size_t argNum, TargetValue &targetVal, cs_detail *detail) const; 44 | TargetValue fetchTargetAddr(cs_detail *detail); 45 | static mnem_type fetchMnemType(const cs_insn &insn); 46 | 47 | const cs_insn m_insn; 48 | size_t m_maxArgs; 49 | 50 | friend class CDisasm; 51 | }; 52 | 53 | }; // namespace minidis 54 | -------------------------------------------------------------------------------- /disasm/cdis/ExeDisasm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CDisasm.h" 4 | 5 | namespace minidis { 6 | 7 | class ExeDisasm : public CDisasm { 8 | public: 9 | ExeDisasm(Executable *exe, offset_t startOffset) : CDisasm(exe, startOffset) {} 10 | 11 | virtual bool init(const offset_t startOffset, const bufsize_t disasmSize) 12 | { 13 | return CDisasm::init(startOffset, disasmSize, m_Exe->getBitMode()); 14 | } 15 | 16 | virtual QString getImportName(offset_t offset, Executable::addr_type aType) const = 0; 17 | virtual bool isImportedFunction(offset_t offset, Executable::addr_type aType) const = 0; 18 | 19 | virtual bool isFollowable(const size_t index) const 20 | { 21 | return CDisasm::isFollowable(index); 22 | } 23 | 24 | bool isBranching(size_t index) 25 | { 26 | mnem_type mType = this->getMnemTypeAtIndex(index); 27 | return CDisasm::isBranching(mType); 28 | } 29 | 30 | bool isBranching(offset_t offset, Executable::addr_type aType) 31 | { 32 | size_t index = this->offsetToIndex(offset, aType); 33 | if (index == INVALID_INDEX) return false; 34 | 35 | mnem_type mType = this->getMnemTypeAtIndex(index); 36 | return CDisasm::isBranching(mType); 37 | } 38 | 39 | bool isFollowable(size_t index) 40 | { 41 | return CDisasm::isFollowable(index); 42 | } 43 | 44 | bool isFollowable(offset_t offset, Executable::addr_type aType) 45 | { 46 | size_t index = this->offsetToIndex(offset, aType); 47 | if (index == INVALID_INDEX) return false; 48 | 49 | return CDisasm::isFollowable(index); 50 | } 51 | }; 52 | 53 | }; /* namespace minidis */ 54 | -------------------------------------------------------------------------------- /disasm/dos/DosDisasm.cpp: -------------------------------------------------------------------------------- 1 | #include "dos/DosDisasm.h" 2 | 3 | using namespace minidis; 4 | 5 | DosDisasm::DosDisasm(DOSExe *dos) 6 | : ExeDisasm(dos, 0), m_dos(dos) 7 | { 8 | if (dos == NULL) throw CustomException("DOS Exe not initialized!"); 9 | } 10 | 11 | bool DosDisasm::fillTable(const DisasmSettings& settings) 12 | { 13 | return ExeDisasm::fillTable(settings); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /disasm/dos/DosTracer.cpp: -------------------------------------------------------------------------------- 1 | #include "dos/DosTracer.h" 2 | 3 | using namespace minidis; 4 | 5 | //---- 6 | 7 | void DosTracer::traceEntrySection() 8 | { 9 | const offset_t codeStart = this->m_dos->convertAddr(0, Executable::RVA, Executable::RAW); 10 | makeDisasmAt(m_dos, codeStart, this->sectionTraceSettings); 11 | traceArea(codeStart); 12 | } 13 | 14 | bool DosTracer::traceFunction(offset_t offset, Executable::addr_type aType, QString name) 15 | { 16 | const offset_t start = this->convertAddr(offset, aType, Executable::RAW); 17 | if (start == INVALID_ADDR) return false; 18 | 19 | if (!makeDisasmAt(m_Exe, start, this->functionTraceSettings)) { 20 | return false; 21 | } 22 | traceArea(start); 23 | return defineFunction(offset, aType, name); 24 | } 25 | 26 | DosDisasm* DosTracer::makeDisasm(Executable* exe, offset_t startRaw) 27 | { 28 | DOSExe *dos = dynamic_cast(exe); 29 | if (!dos) return NULL; 30 | DosDisasm *disasm = new DosDisasm(dos); 31 | bufsize_t size = dos->getContentSize() - startRaw; 32 | if (!disasm->init(startRaw, size)) { 33 | delete disasm; 34 | disasm = NULL; 35 | } 36 | return disasm; 37 | } 38 | -------------------------------------------------------------------------------- /disasm/include/AddrConverter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define INVALID_INDEX (-1) 6 | 7 | namespace minidis { 8 | 9 | class AddrConverter { 10 | public: 11 | virtual offset_t convertAddr(offset_t off, Executable::addr_type inType, Executable::addr_type outType) const = 0; 12 | virtual Executable::addr_type detectAddrType(offset_t off, Executable::addr_type hintType) const = 0; 13 | }; 14 | 15 | }; /* namespace pe_bear */ 16 | -------------------------------------------------------------------------------- /disasm/include/CodeBlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define INVALID_INDEX (-1) 7 | 8 | namespace minidis { 9 | 10 | class ForkPoint 11 | { 12 | public: 13 | ForkPoint() 14 | : forkOffset(INVALID_ADDR), yesOffset(INVALID_ADDR), noOffset(INVALID_ADDR){ ; } 15 | 16 | ForkPoint(offset_t v_forkOffset, offset_t v_yesOffset, offset_t v_noOffset) 17 | : forkOffset(v_forkOffset), yesOffset(v_yesOffset), noOffset(v_noOffset) 18 | { 19 | //printf("Fork at %x -> (%x | %x)\n", forkOffset, yesOffset, noOffset); 20 | } 21 | 22 | offset_t forkOffset; 23 | offset_t yesOffset; 24 | offset_t noOffset; 25 | }; 26 | 27 | class CodeBlock { 28 | 29 | public: 30 | CodeBlock() : start(INVALID_ADDR), size(0) {} 31 | CodeBlock(offset_t v_start) : start(v_start), size(0), m_isInvalid(false) {} 32 | 33 | bool append(offset_t offset) 34 | { 35 | if (offset == INVALID_ADDR) return false; 36 | 37 | this->offsets << offset; 38 | this->size = offset - start; 39 | return true; 40 | } 41 | 42 | bool contains(offset_t offset) { return offsets.contains(offset); } 43 | 44 | offset_t getEndOffset() 45 | { 46 | if (offsets.size() == 0) return INVALID_INDEX; 47 | return offsets.back(); 48 | } 49 | 50 | void markInvalid() { m_isInvalid = true; } 51 | bool isInvalid() { return m_isInvalid; } 52 | 53 | int getIndexOf(offset_t offset) 54 | { 55 | const int index = offsets.indexOf(offset); 56 | if (index == -1) return INVALID_INDEX; 57 | return index; 58 | } 59 | 60 | Executable::addr_type getAddrType() { return Executable::RAW; } //block keeps RAW offsets 61 | 62 | offset_t start; 63 | offset_t size; 64 | 65 | QList offsets; 66 | protected: 67 | bool m_isInvalid; 68 | }; 69 | 70 | }; /* namespace minidis */ 71 | -------------------------------------------------------------------------------- /disasm/include/Context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace minidis { 6 | 7 | enum flag_val { FLAG_UNK = 0, FLAG_UNSET = (-1), FLAG_SET = 1, FLAG_REL, FLAG_RELNEG }; 8 | 9 | struct cond_buf { 10 | flag_val CF, PF, AF, ZF, SF, IF, DF, OF; 11 | int8_t cx; 12 | int8_t affectedCounter; 13 | }; 14 | 15 | void resetCond(cond_buf &buf); 16 | 17 | }; /* namespace minidis */ 18 | -------------------------------------------------------------------------------- /disasm/include/DisasmBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "DisasmChunkBuf.h" 6 | 7 | #include "AddrConverter.h" 8 | #include "FuncNameManager.h" 9 | 10 | // maximal number of chunks that the disassembler is allowed to generate at the time 11 | 12 | #define MAX_DISASM_EL 1000 13 | 14 | namespace minidis { 15 | //------------------------------------------------ 16 | 17 | class DisasmSettings { 18 | public: 19 | DisasmSettings() 20 | { 21 | m_maxDisasmElements = MAX_DISASM_EL; 22 | m_stopAtBlockEnd = true; 23 | m_stopAtFuncEnd = true; 24 | } 25 | 26 | DisasmSettings(size_t maxElements, bool stopAtBlockEnd, bool stopAtFuncEnd) 27 | { 28 | if (maxElements == 0) maxElements = MAX_DISASM_EL; 29 | m_maxDisasmElements = maxElements; 30 | m_stopAtBlockEnd = stopAtBlockEnd; 31 | m_stopAtFuncEnd = stopAtFuncEnd; 32 | } 33 | 34 | size_t getMaxDisasmElements() const 35 | { 36 | return m_maxDisasmElements; 37 | } 38 | 39 | bool isStopAtBlockEnd() const 40 | { 41 | return m_stopAtBlockEnd; 42 | } 43 | 44 | bool isStopAtFuncEnd() const 45 | { 46 | return m_stopAtFuncEnd; 47 | } 48 | 49 | protected: 50 | size_t m_maxDisasmElements; 51 | bool m_stopAtBlockEnd; 52 | bool m_stopAtFuncEnd; 53 | 54 | friend class Tracer; 55 | friend class DisasmBase; 56 | }; 57 | 58 | 59 | /* abstract class, base of all the Disasms*/ 60 | class DisasmBase : public AddrConverter 61 | { 62 | public: 63 | /* static*/ 64 | const static size_t MAX_ARG_NUM; 65 | 66 | static bool isBlockRet(const mnem_type &mType); 67 | static bool isBlockEnd(const mnem_type &mType); 68 | static bool isJump(const mnem_type &mType); 69 | 70 | static bool isBranching(const mnem_type &mType); 71 | static bool isConditionalBranching(const mnem_type &mType); 72 | static bool isUnconditionalBranching(const mnem_type &mType); 73 | 74 | static QString getStringAt(Executable *exe, offset_t target, Executable::addr_type aType); 75 | 76 | /* non-static */ 77 | DisasmBase(Executable* exe, offset_t startOffset) : 78 | m_Exe(exe), m_startOffset(startOffset), 79 | is_init(false), 80 | m_addrType(Executable::RAW)//,m_nameManager(this) 81 | { 82 | } 83 | 84 | virtual ~DisasmBase() 85 | { 86 | is_init = false; 87 | } 88 | 89 | DisasmChunk* getChunkAtIndex(size_t index) const 90 | { 91 | return m_disasmBuf.at(index); 92 | } 93 | 94 | QString getStringAt(offset_t target, Executable::addr_type aType) 95 | { 96 | return DisasmBase::getStringAt(this->m_Exe, target, aType); 97 | } 98 | 99 | virtual bool isBranching(offset_t offset, Executable::addr_type aType) = 0; 100 | 101 | /** 102 | * @brief fills table of disassembly chunks 103 | * @param settings set of conditions at which te filling of the table should stop 104 | * @return true if successful 105 | */ 106 | virtual bool fillTable(const DisasmSettings &settings); 107 | 108 | virtual void clearTable() 109 | { 110 | m_disasmBuf.clear(); 111 | } 112 | 113 | size_t offsetToIndex(const offset_t inOffset, Executable::addr_type inType) const 114 | { 115 | offset_t offset = this->convertAddr(inOffset, inType, m_addrType); 116 | return m_disasmBuf.offsetToIndex(offset); 117 | } 118 | 119 | //virtual cond_buf Disasm::getCond(offset_t offset, Executable::addr_type inType) const = 0; //TODO 120 | virtual mnem_type getMnemTypeAtIndex(const size_t index) const 121 | { 122 | DisasmChunk* chunk = this->m_disasmBuf.at(index); 123 | if (!chunk) { 124 | return MT_NONE; 125 | } 126 | return chunk->getMnemType(); 127 | } 128 | 129 | virtual mnem_type getMnemTypeAtOffset(offset_t offset, Executable::addr_type inType) const 130 | { 131 | size_t index = offsetToIndex(offset, inType); 132 | if (index == INVALID_INDEX) return MT_NONE; 133 | 134 | return getMnemTypeAtIndex(index); 135 | } 136 | 137 | virtual offset_t convertAddr(offset_t off, Executable::addr_type inType, Executable::addr_type outType) const 138 | { 139 | return m_Exe->convertAddr(off, inType, outType); 140 | } 141 | 142 | virtual Executable::addr_type detectAddrType(offset_t off, Executable::addr_type hintType) const 143 | { 144 | return m_Exe->detectAddrType(off, hintType); 145 | } 146 | 147 | virtual bool isFollowable(const size_t y) const; 148 | 149 | //wrapper: 150 | virtual bool isFollowable(offset_t offset, Executable::addr_type aType) const 151 | { 152 | offset = this->convertAddr(offset, aType, Executable::RAW); 153 | size_t index = this->m_disasmBuf.offsetToIndex(offset); 154 | return isFollowable(index); 155 | } 156 | 157 | virtual offset_t getTargetOffset(const size_t index, Executable::addr_type aType) const; 158 | 159 | virtual offset_t getOffset(const size_t index, const Executable::addr_type aType = Executable::RAW) const 160 | { 161 | const DisasmChunk *chunk = this->getChunkAtIndex(index); 162 | if (!chunk) return INVALID_ADDR; 163 | 164 | const offset_t raw = m_disasmBuf.indexToOffset(index); 165 | return this->convertAddr(raw, Executable::RAW, aType); 166 | } 167 | 168 | virtual offset_t getNextOffset(const size_t index, const Executable::addr_type aType = Executable::RAW) const 169 | { 170 | if (!m_Exe) return INVALID_ADDR; 171 | 172 | DisasmChunk *chunk = this->getChunkAtIndex(index); 173 | if (!chunk) return INVALID_ADDR; 174 | 175 | offset_t raw = getOffset(index, Executable::RAW); 176 | if (raw == INVALID_ADDR) return INVALID_ADDR; 177 | 178 | raw += chunk->getChunkSize(); 179 | if (raw >= m_Exe->getContentSize()) return INVALID_ADDR; 180 | 181 | return this->convertAddr(raw, Executable::RAW, aType); 182 | } 183 | 184 | virtual bool isPushRet(int pushIndex) const; // equivalent of CALL 185 | virtual bool isCallToRet(const size_t callIndex) const; // equivalent of NOP 186 | 187 | //virtual QString translateBranching(const size_t index, FuncNameManager *nameManager = NULL) const = 0; 188 | bufsize_t getChunkSize(const size_t index) const { return this->m_disasmBuf.getChunkSize(index); } 189 | 190 | bool hasOffset(offset_t offset) { return (m_disasmBuf.offsetToIndex(offset) != INVALID_INDEX); } 191 | 192 | virtual bool isImportCall(size_t index) { return false; } 193 | virtual bool isImportedFunction(offset_t offset, Executable::addr_type aType) const { return false; } 194 | virtual bool isImportCall(offset_t offset, Executable::addr_type inType); 195 | virtual bool isInternalCall(offset_t offset, Executable::addr_type inType); 196 | virtual bool isInterruptX(size_t index); 197 | 198 | /* wrappers */ 199 | bool isBlockRet(const size_t index) const { return isBlockRet(getMnemTypeAtIndex(index)); } 200 | bool isBlockEnd(const size_t index) const { return isBlockEnd(getMnemTypeAtIndex(index)); } 201 | bool isJump(const size_t index) const { return isJump(getMnemTypeAtIndex(index)); } 202 | 203 | virtual bool isBranching(size_t index) = 0; 204 | bool isConditionalBranching(size_t index) const { return isConditionalBranching(getMnemTypeAtIndex(index)); } 205 | bool isUnconditionalBranching(size_t index) const { return isUnconditionalBranching(getMnemTypeAtIndex(index)); } 206 | 207 | target_state getTargetState(const size_t index) const; //TODO: refactor it 208 | //---- 209 | DisasmChunkBuf m_disasmBuf; 210 | 211 | protected: 212 | virtual DisasmChunk* makeChunk(offset_t startRVA) = 0; 213 | 214 | // distance between current RVA and Target RVA 215 | int32_t getTargetDelta(const size_t index) const; 216 | 217 | static uint64_t trimToBitMode(int64_t value, Executable::exe_bits bits); 218 | //--- 219 | virtual size_t disasmNext() = 0; 220 | bool isOpToRet(const int index, const mnem_type op) const; 221 | virtual offset_t getImmediate(offset_t val, Executable::addr_type outType, Executable::addr_type hintType) const; 222 | 223 | bool is_init; 224 | Executable::exe_bits m_bitMode; 225 | Executable::addr_type m_addrType; 226 | offset_t m_startOffset; 227 | Executable* m_Exe; 228 | 229 | }; /* class DisasmBase */ 230 | 231 | }; /* namespace minidis */ 232 | -------------------------------------------------------------------------------- /disasm/include/DisasmChunk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "AddrConverter.h" 6 | #include "MnemType.h" 7 | #include "Context.h" 8 | #include "TargetValue.h" 9 | 10 | namespace minidis { 11 | 12 | class DisasmChunk : public AddrConverter { 13 | public: 14 | const static size_t MAX_ARG_NUM; 15 | 16 | DisasmChunk(offset_t startOffset, Executable *parent) 17 | : m_Exe(parent), m_startOffset(startOffset), m_bitMode(parent->getBitMode()) 18 | { 19 | } 20 | 21 | virtual ~DisasmChunk() {} 22 | 23 | /*inherited from AddrConverter */ 24 | virtual offset_t convertAddr(offset_t off, Executable::addr_type inType, Executable::addr_type outType) const 25 | { 26 | if (!m_Exe) return off; 27 | return m_Exe->convertAddr(off, inType, outType); 28 | } 29 | 30 | virtual Executable::addr_type detectAddrType(offset_t off, Executable::addr_type hintType) const 31 | { 32 | if (!m_Exe) return hintType; 33 | return m_Exe->detectAddrType(off, hintType); 34 | } 35 | //--- 36 | virtual bool isValidAddr(offset_t addr, Executable::addr_type aType) const 37 | { 38 | if (!m_Exe) return false; 39 | return m_Exe->isValidAddr(addr, aType); 40 | 41 | } 42 | offset_t getImmediate(offset_t lval, Executable::addr_type outType, Executable::addr_type hintType) const; 43 | 44 | virtual bufsize_t getChunkSize() const = 0; 45 | virtual QString translateBranchingMnemonic() const = 0; 46 | 47 | virtual QString toString() 48 | { 49 | //lazy init 50 | if (m_disasmString.length() == 0) initStrings(); 51 | return m_disasmString; 52 | } 53 | 54 | virtual QString toHexString() 55 | { 56 | //lazy init 57 | if (m_hexStr.length() == 0) initStrings(); 58 | return m_hexStr; 59 | } 60 | 61 | virtual mnem_type getMnemType() const { return this->m_mnemType; } 62 | 63 | 64 | virtual bool isBranching() const; 65 | virtual bool isConditionalBranching() const; 66 | virtual bool isUnconditionalBranching() const; 67 | virtual bool isJump() const; 68 | 69 | bool isFuncEnd() const; 70 | bool isRet() const; 71 | 72 | offset_t getTargetRaw() const { return this->m_targetVal.getTargetRaw(); } 73 | offset_t getTargetAddr() const { return this->m_targetVal.getTargetAddr(); } 74 | Executable::addr_type getTargetAddrType() const { return m_targetVal.getAddrType(); } 75 | bool isTargetImm() const {return m_targetVal.isImm(); } 76 | 77 | protected: 78 | QString printBytes(const uint8_t* buf, const size_t size) const 79 | { 80 | QString str; 81 | for (size_t i = 0; i < size; i++) { 82 | str += QString().asprintf("%02X", buf[i]); 83 | } 84 | return str; 85 | } 86 | //--- 87 | /* 88 | virtual void init() 89 | { 90 | m_mnemType = fetchMnemType(); 91 | m_targetVal = fetchTargetAddr(); 92 | } 93 | */ 94 | virtual void initStrings() = 0; 95 | 96 | virtual mnem_type fetchMnemType() const = 0; 97 | virtual size_t getMaxArg() = 0; 98 | //virtual bool fetchTargetAddr(const size_t argNum, TargetValue &targetVal) const = 0; 99 | //virtual TargetValue fetchTargetAddr() = 0; 100 | 101 | uint64_t trimToBitMode(int64_t value, Executable::exe_bits bits) const 102 | { 103 | uint64_t lval = value; 104 | const size_t max_bits = sizeof(lval) * 8; 105 | const size_t dif = max_bits - bits; 106 | lval = (lval << dif) >> dif; 107 | return lval; 108 | } 109 | 110 | int64_t signExtend(int64_t operand, size_t opSize) const 111 | { 112 | size_t opBits = opSize * 8; 113 | int64_t lval = operand; 114 | size_t dif = sizeof(lval) * 8 - opBits; 115 | lval = (operand << dif) >> dif; 116 | return lval; 117 | } 118 | 119 | bool setTargetVal(TargetValue &targetVal, const size_t argNum, Executable::addr_type aType, int64_t lval, bool isImm = false) const 120 | { 121 | if (lval == INVALID_ADDR) { 122 | targetVal.setValues(argNum, aType, INVALID_ADDR, INVALID_ADDR, isImm); 123 | return false; 124 | } 125 | 126 | offset_t raw = this->convertAddr(lval, aType, Executable::RAW); 127 | targetVal.setValues(argNum, aType, lval, raw, isImm); 128 | return true; 129 | } 130 | 131 | virtual offset_t getOffset() const = 0; 132 | //--- 133 | TargetValue m_targetVal; 134 | offset_t m_startOffset; 135 | 136 | QString m_disasmString, m_hexStr; 137 | mnem_type m_mnemType; 138 | 139 | Executable::exe_bits m_bitMode; 140 | Executable* m_Exe; 141 | 142 | friend class DisasmChunkBuf; 143 | }; 144 | 145 | //--- 146 | }; // namespace minidis 147 | -------------------------------------------------------------------------------- /disasm/include/DisasmChunkBuf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "DisasmChunk.h" 5 | 6 | namespace minidis { 7 | //--- 8 | class DisasmChunkBuf 9 | { 10 | public: 11 | DisasmChunkBuf() : m_offset(0) {} 12 | ~DisasmChunkBuf() {} 13 | 14 | const DisasmChunk* objAt(const size_t index) const 15 | { 16 | return (m_table.size() > index) ? m_table.at(index) : NULL; 17 | } 18 | 19 | size_t size() const { return m_table.size(); } 20 | 21 | DisasmChunk* at(size_t index) const 22 | { 23 | if (index >= m_table.size()) { 24 | return NULL; 25 | } 26 | return m_table.at(index); 27 | } 28 | 29 | void clear() { m_table.clear(); } 30 | void append(DisasmChunk *chunk); 31 | 32 | void setStartOffset(offset_t offset) { m_offset = offset; } 33 | offset_t getStartOffset() const { return m_offset; } 34 | 35 | offset_t indexToOffset(const size_t index) const; 36 | size_t offsetToIndex(const offset_t raw) const; 37 | 38 | bufsize_t getChunkSize(const size_t index) const; 39 | QString getDisasmString(const size_t index); 40 | 41 | protected: 42 | offset_t m_offset; // buffer start offset 43 | std::vector m_table; 44 | std::map m_offsetToIndex; // RAW -> index 45 | }; 46 | 47 | //--- 48 | }; // namespace minidis 49 | -------------------------------------------------------------------------------- /disasm/include/FuncNameManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace minidis { 7 | 8 | class AddrConverter; 9 | //---------------------------------------------- 10 | 11 | class FuncNameManager 12 | { 13 | public: 14 | FuncNameManager(AddrConverter *converter) 15 | : m_Converter(converter), m_aType(Executable::RAW) { } 16 | virtual ~FuncNameManager() {} 17 | 18 | bool setFunctionName(offset_t offset, Executable::addr_type inType, QString name); 19 | bool hasName(offset_t offset, Executable::addr_type inType) const; 20 | QString getFunctionName(offset_t offset, Executable::addr_type inType) const; 21 | QList& getNamedOffsetsList() { return m_namedOffsetsList; } 22 | 23 | size_t save(const QString &fileName); 24 | size_t load(const QString &fileName); 25 | 26 | protected: 27 | AddrConverter *m_Converter; 28 | QMap nameToFunction; 29 | QMap functionToName; 30 | Executable::addr_type m_aType; 31 | QList m_namedOffsetsList; 32 | }; 33 | 34 | class FuncManager 35 | { 36 | public: 37 | FuncManager(AddrConverter *converter); 38 | bool appendFunction(offset_t offset, Executable::addr_type inType); 39 | 40 | Executable::addr_type getAddrType(); 41 | QList& list() { return m_functionsList; } 42 | 43 | protected: 44 | AddrConverter *m_Converter; 45 | 46 | QList m_functionsList; 47 | QSet m_functions; 48 | Executable::addr_type m_aType; 49 | }; 50 | 51 | }; //namespace minidis 52 | -------------------------------------------------------------------------------- /disasm/include/MnemType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace minidis { 5 | 6 | const BYTE OP_RET = 0xc3; 7 | 8 | enum mnem_type { 9 | MT_INVALID, // invalid instruction 10 | MT_RET, 11 | MT_NOP, 12 | MT_INTX, 13 | MT_INT3, 14 | MT_CALL, 15 | MT_JUMP, 16 | MT_COND_JUMP, 17 | MT_LOOP, 18 | MT_PUSH, 19 | MT_POP, 20 | MT_ARITHMETICAL, 21 | MT_MOV, 22 | MT_TEST, 23 | MT_OTHER, 24 | MT_NONE, // invalid input 25 | COUNT_MT 26 | }; 27 | 28 | }; /* namespace minidis */ 29 | -------------------------------------------------------------------------------- /disasm/include/TargetValue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace minidis { 6 | 7 | enum target_state { 8 | TS_NOT_ADDR, 9 | TS_VIRTUAL_ONLY, //cannot be converted to raw 10 | TS_VALID, 11 | COUNT_TS 12 | }; 13 | 14 | class TargetValue 15 | { 16 | public: 17 | TargetValue() : m_targetAddrType(Executable::NOT_ADDR), 18 | m_targetOpNum(0), m_isImm(false), 19 | m_targetAddr(INVALID_ADDR), m_targetRaw(INVALID_ADDR) {} 20 | 21 | virtual ~TargetValue() {} 22 | 23 | Executable::addr_type getAddrType() const {return m_targetAddrType; } 24 | offset_t getTargetAddr() const { return m_targetAddr; } 25 | offset_t getTargetRaw() const { return m_targetRaw; } //converted 26 | 27 | size_t getOpNum() const { return m_targetOpNum; } 28 | bool isImm() const { return m_isImm; } 29 | target_state getState() 30 | { 31 | if (m_targetAddr == INVALID_ADDR) return TS_NOT_ADDR; 32 | if (m_targetRaw == INVALID_ADDR) return TS_VIRTUAL_ONLY; 33 | return TS_VALID; 34 | } 35 | 36 | void setValues(size_t targetOpNum, Executable::addr_type targetAddrType, offset_t targetAddr, offset_t targetRaw, bool isImm = false) 37 | { 38 | m_targetAddrType = targetAddrType; //should be VA or RVA 39 | m_targetAddr = targetAddr; 40 | m_targetRaw = targetRaw; 41 | m_targetOpNum = targetOpNum; 42 | m_isImm = isImm; 43 | } 44 | 45 | // values: 46 | Executable::addr_type m_targetAddrType; // original type 47 | offset_t m_targetAddr; //original addr 48 | offset_t m_targetRaw; 49 | size_t m_targetOpNum; 50 | bool m_isImm; 51 | }; 52 | //--- 53 | }; // namespace minidis 54 | -------------------------------------------------------------------------------- /disasm/include/Tracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "CodeBlock.h" 9 | #include "DisasmBase.h" 10 | 11 | 12 | namespace minidis { 13 | 14 | class Tracer : public QObject, public AddrConverter 15 | { 16 | Q_OBJECT 17 | 18 | signals: 19 | void loadingProgress(int progress); 20 | 21 | public: 22 | Tracer(Executable *exe) : QObject(), AddrConverter(), 23 | m_Exe(exe), 24 | m_nameManager(this), m_funcManager(this), m_impFuncManager(this), 25 | functionTraceSettings(), sectionTraceSettings() 26 | { 27 | m_bitMode = m_Exe->getBitMode(); 28 | 29 | functionTraceSettings.m_stopAtBlockEnd = false; 30 | functionTraceSettings.m_stopAtFuncEnd = true; 31 | 32 | sectionTraceSettings.m_stopAtBlockEnd = false; 33 | sectionTraceSettings.m_stopAtFuncEnd = false; 34 | } 35 | 36 | virtual ~Tracer() {} 37 | 38 | bool resolveOffset(offset_t offset, Executable::addr_type aType); 39 | 40 | QString getStringAt(offset_t target); 41 | 42 | /* conversion */ 43 | virtual offset_t convertAddr(offset_t off, Executable::addr_type inType, Executable::addr_type outType) const 44 | { 45 | return m_Exe->convertAddr(off, inType, outType); 46 | } 47 | 48 | virtual Executable::addr_type detectAddrType(offset_t off, Executable::addr_type hintType) const 49 | { 50 | return m_Exe->detectAddrType(off, hintType); 51 | } 52 | 53 | virtual DisasmBase* getDisasmAt(offset_t offset, Executable::addr_type inType = Executable::RAW) const; 54 | 55 | virtual minidis::mnem_type getMnemTypeAtOffset(offset_t offset, Executable::addr_type inType) 56 | { 57 | offset = this->convertAddr(offset, inType, Executable::RAW); 58 | DisasmBase* dis = getDisasmAt(offset); 59 | if (!dis) return MT_OTHER; 60 | return dis->getMnemTypeAtOffset(offset, inType); 61 | } 62 | 63 | QString getHexString(offset_t offset, Executable::addr_type aType) 64 | { 65 | offset = this->convertAddr(offset, aType, Executable::RAW); 66 | DisasmBase* dis = getDisasmAt(offset); 67 | if (!dis) return NULL; 68 | 69 | size_t index = dis->m_disasmBuf.offsetToIndex(offset); 70 | if (index == INVALID_INDEX) return "?"; 71 | 72 | DisasmChunk *chunk = dis->getChunkAtIndex(index); 73 | if (!chunk) return ":("; 74 | return dis->getChunkAtIndex(index)->toHexString(); 75 | } 76 | 77 | QString translateBranching(DisasmBase* dis, const size_t index, FuncNameManager *nameManager) const; 78 | 79 | virtual QString getDisasmString(offset_t offset, Executable::addr_type aType) 80 | { 81 | offset = this->convertAddr(offset, aType, Executable::RAW); 82 | DisasmBase* dis = getDisasmAt(offset); 83 | if (!dis) return NULL; 84 | 85 | size_t index = dis->m_disasmBuf.offsetToIndex(offset); 86 | if (index == INVALID_INDEX) return "?"; 87 | 88 | QString str; 89 | bool isBranching = dis->isBranching(offset, Executable::RAW); 90 | const offset_t target = dis->getTargetOffset(index, Executable::RAW); 91 | 92 | if (isBranching) { 93 | str = translateBranching(dis, index, &this->m_nameManager); 94 | } else { 95 | str = dis->m_disasmBuf.getDisasmString(index); 96 | } 97 | if (isImportedFunction(target, Executable::RAW)) { 98 | return str + " -> " + getImportName(target, Executable::RAW); 99 | } 100 | 101 | if (!isBranching && this->hasName(target, Executable::RAW)) { 102 | return str + " -> " + this->getFunctionName(target, Executable::RAW); 103 | } 104 | 105 | return str; 106 | } 107 | 108 | virtual bool isInternalCall(offset_t offset, Executable::addr_type inType); 109 | 110 | virtual offset_t getTargetOffset(offset_t offset, Executable::addr_type inType, Executable::addr_type outType) 111 | { 112 | offset = this->convertAddr(offset, inType, Executable::RAW); 113 | DisasmBase* dis = getDisasmAt(offset); 114 | if (!dis) return INVALID_ADDR; 115 | 116 | size_t index = dis->m_disasmBuf.offsetToIndex(offset); 117 | if (index == INVALID_INDEX) return INVALID_ADDR; 118 | 119 | return dis->getTargetOffset(index, outType); 120 | } 121 | 122 | virtual bool isBranching(offset_t offset, Executable::addr_type inType) const { 123 | offset = this->convertAddr(offset, inType, Executable::RAW); 124 | DisasmBase* dis = getDisasmAt(offset); 125 | if (!dis) return false; 126 | 127 | return dis->isBranching(offset, Executable::RAW); 128 | } 129 | 130 | virtual bool isFollowable(offset_t offset, Executable::addr_type inType) const { 131 | offset = this->convertAddr(offset, inType, Executable::RAW); 132 | DisasmBase* dis = getDisasmAt(offset); 133 | if (!dis) return false; 134 | 135 | return dis->isFollowable(offset, Executable::RAW); 136 | } 137 | 138 | virtual bool isImportedFunction(offset_t offset, Executable::addr_type aType) const = 0; 139 | virtual QString getImportName(offset_t offset, Executable::addr_type aType) const = 0; 140 | 141 | QList& blocksList() { return this->m_validBlocksOffsets; } 142 | 143 | CodeBlock* blockStartingAt(offset_t offset, Executable::addr_type aType = Executable::RAW) 144 | { 145 | const offset_t raw = this->convertAddr(offset, aType, Executable::RAW); 146 | if (raw == INVALID_ADDR) { 147 | return NULL; 148 | } 149 | return m_blocks.contains(raw) ? &m_blocks[raw] : NULL; 150 | } 151 | 152 | CodeBlock* blockAt(offset_t offset, Executable::addr_type aType = Executable::RAW) 153 | { 154 | if (offset == INVALID_ADDR) { 155 | return NULL; 156 | } 157 | offset_t raw = this->convertAddr(offset, aType, Executable::RAW); 158 | 159 | //give priority to block starting at given offset 160 | CodeBlock *block = blockStartingAt(offset, aType); 161 | if (block) { 162 | return block; 163 | } 164 | return m_blockPtrs.contains(raw) ? m_blockPtrs[raw] : NULL; 165 | } 166 | 167 | ForkPoint* forkAt(offset_t raw) { return m_forks.contains(raw) ? &m_forks[raw] : NULL; } 168 | 169 | QSet* refsTo(offset_t offset, Executable::addr_type aType) 170 | { 171 | offset_t raw = convertAddr(offset, aType, Executable::RAW); 172 | return m_refs.contains(raw) ? &m_refs[raw] : NULL; 173 | } 174 | 175 | QSet* refBlocksTo(offset_t offset, Executable::addr_type aType) 176 | { 177 | offset_t raw = convertAddr(offset, aType, Executable::RAW); 178 | return m_refBlocks.contains(raw) ? &m_refBlocks[raw] : NULL; 179 | } 180 | 181 | bool hasName(offset_t offset, Executable::addr_type inType) const 182 | { 183 | return m_nameManager.hasName(offset, inType); 184 | } 185 | 186 | QString getFunctionName(offset_t offset, Executable::addr_type inType) const 187 | { 188 | return m_nameManager.getFunctionName(offset, inType); 189 | } 190 | 191 | bool hasReferedString(offset_t offset, Executable::addr_type inType) const 192 | { 193 | offset = convertAddr(offset, inType, Executable::RAW); 194 | return (this->m_referedStrings.contains(offset)); 195 | } 196 | 197 | QString getReferedString(offset_t offset, Executable::addr_type inType) const 198 | { 199 | offset = convertAddr(offset, inType, Executable::RAW); 200 | if (!this->m_referedStrings.contains(offset)) return "?"; 201 | 202 | return m_referedStrings[offset]; 203 | } 204 | 205 | virtual size_t findAllPrologs(QSet &prologOffsets) { return 0; } 206 | virtual void traceEntrySection() = 0; 207 | virtual bool traceFunction(offset_t offset, Executable::addr_type aType, QString name) = 0; 208 | virtual bool defineFunction(offset_t offset, Executable::addr_type aType, QString name); 209 | 210 | QList& getFunctionsList() { return m_funcManager.list(); } 211 | QList& getImpFunctionsList() { return m_impFuncManager.list(); } 212 | QList& getReferedStringsList() { return m_referedStringsList; } 213 | QList& getNamedOffsetsList() { return m_nameManager.getNamedOffsetsList(); } 214 | 215 | bool resolveUnsolved(const size_t maxDepth, const size_t maxUnsolved) 216 | { 217 | emit loadingProgress(0); 218 | int progress = 0; 219 | int progressChunk = 100 / maxDepth; 220 | 221 | size_t depth = 0; 222 | QSet unsolved = m_unsolvedOffsets; 223 | while (depth++ < maxDepth) { 224 | fetchUnsolved(unsolved); 225 | std::cout <<"Depth: " << std::dec << depth << " unsolved : " << unsolved.size() << std::endl; 226 | if (unsolved.size() == 0) { 227 | return true; 228 | } 229 | if (unsolved.size() > maxUnsolved) { 230 | std::cout << "Unsolved limit exceeded: " << std::dec << unsolved.size() << std::endl; 231 | break; 232 | } 233 | resolveUnsolvedBranches(unsolved); 234 | unsolved.clear(); 235 | progress += progressChunk; 236 | emit loadingProgress(progress); 237 | } 238 | return false; 239 | } 240 | 241 | size_t saveFunctionNames(const QString &fileName) { return m_nameManager.save(fileName); } 242 | size_t loadFunctionNames(const QString &fileName) { return m_nameManager.load(fileName); } 243 | 244 | bool setSingleFunctionName(offset_t offset, Executable::addr_type inType, QString name) 245 | { 246 | if (offset == this->m_Exe->getEntryPoint(inType) && hasName(offset, inType)) { 247 | return false; // do not change name at EP 248 | } 249 | return m_nameManager.setFunctionName(offset, inType, name); 250 | } 251 | 252 | protected: 253 | 254 | bool appendCodeChunk(DisasmBase* disasm, CodeBlock* block, const offset_t currOff); 255 | 256 | virtual DisasmBase* makeDisasm(Executable* exe, offset_t startRaw) = 0; 257 | size_t fetchUnsolved(QSet &unresolvedSet); 258 | virtual size_t resolveUnsolvedBranches(const QSet &unsolved); 259 | 260 | bool makeDisasmAt(Executable* exe, offset_t raw, DisasmSettings &settings); 261 | 262 | void addReferencedTargets(offset_t currOffset, offset_t target, DisasmChunk *chunk); 263 | void traceArea(offset_t start); 264 | 265 | /* references */ 266 | void addReference(offset_t offset, offset_t calledAt) 267 | { 268 | if (offset == INVALID_ADDR || calledAt == INVALID_ADDR) return; 269 | m_refs[offset].insert(calledAt); 270 | } 271 | 272 | void addForkPoint(offset_t currOff, offset_t target, offset_t next); 273 | 274 | void traceBlocks(DisasmBase* disasm, offset_t startOffset); 275 | CodeBlock* getOrMakeCodeBlockAt(offset_t offset); 276 | void filterValidBlocks(); 277 | void traceReferencedCodeBlocks(); 278 | 279 | FuncNameManager m_nameManager; 280 | FuncManager m_funcManager; 281 | FuncManager m_impFuncManager; 282 | 283 | QList forksList; 284 | 285 | // basic keepers 286 | QMap m_offsetToDisasm; 287 | QMap m_blocks; 288 | QMap > m_refs; 289 | QMap m_forks; 290 | QSet m_unsolvedOffsets; 291 | QMap m_referedStrings; 292 | 293 | // helpers for faster access 294 | QList m_referedStringsList; 295 | QList m_validBlocksOffsets; 296 | QSet m_validBlocksOffsetsSet; 297 | 298 | QMap m_disasmPtrs; 299 | QMap m_blockPtrs; 300 | QMap > m_refBlocks; 301 | 302 | Executable::exe_bits m_bitMode; 303 | Executable *m_Exe; 304 | 305 | DisasmSettings functionTraceSettings; 306 | DisasmSettings sectionTraceSettings; 307 | 308 | }; /* class Tracer */ 309 | 310 | }; /* namespace minidis */ 311 | -------------------------------------------------------------------------------- /disasm/include/beardisasm.h: -------------------------------------------------------------------------------- 1 | #ifndef BEARDISASM_H 2 | #define BEARDISASM_H 3 | 4 | #include "AddrConverter.h" 5 | #include "CodeBlock.h" 6 | #include "Context.h" 7 | #include "DisasmBase.h" 8 | #include "DisasmChunk.h" 9 | #include "DisasmChunkBuf.h" 10 | #include "Tracer.h" 11 | 12 | #include "dos/DosDisasm.h" 13 | #include "dos/DosTracer.h" 14 | 15 | #include "pe/PeDataFetcher.h" 16 | #include "pe/PeDisasm.h" 17 | #include "pe/PeTracer.h" 18 | 19 | #endif //BEARDISASM_H 20 | -------------------------------------------------------------------------------- /disasm/include/dos/DosDisasm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../ExeDisasm.h" 4 | 5 | #include 6 | 7 | #define PREVIEW_SIZE 0x200 8 | 9 | namespace minidis { 10 | 11 | class DosDisasm : public ExeDisasm 12 | { 13 | 14 | public: 15 | DosDisasm(DOSExe *dos); 16 | 17 | bool fillTable(const DisasmSettings& settings); 18 | 19 | virtual bool isImportedFunction(offset_t offset, Executable::addr_type aType) const 20 | { 21 | return false; 22 | } 23 | 24 | virtual QString getImportName(offset_t offset, Executable::addr_type aType) const 25 | { 26 | return "?"; 27 | } 28 | 29 | virtual bool isImportCall(size_t index) 30 | { 31 | return false; 32 | } 33 | 34 | protected: 35 | DOSExe *m_dos; 36 | 37 | }; /* class DosDisasm */ 38 | 39 | }; /* namespace minidis */ 40 | 41 | -------------------------------------------------------------------------------- /disasm/include/dos/DosTracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Tracer.h" 7 | #include "DosDisasm.h" 8 | 9 | namespace minidis { 10 | 11 | class DosTracer : public Tracer 12 | { 13 | public: 14 | DosTracer(DOSExe *exe) 15 | : Tracer(exe) , m_dos(exe){ } 16 | 17 | void traceEntrySection(); 18 | bool traceFunction(offset_t offset, Executable::addr_type aType, QString name); 19 | 20 | virtual bool isImportedFunction(offset_t offset, Executable::addr_type aType) const 21 | { 22 | return false; 23 | } 24 | 25 | virtual QString getImportName(offset_t offset, Executable::addr_type aType) const 26 | { 27 | return "?"; 28 | } 29 | 30 | protected: 31 | virtual DosDisasm* makeDisasm(Executable* exe, offset_t startRaw); 32 | 33 | DOSExe *m_dos; 34 | }; 35 | 36 | }; /* namespace minidis */ 37 | -------------------------------------------------------------------------------- /disasm/include/pe/PeDataFetcher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace minidis { 6 | 7 | class PeDataFetcher 8 | { 9 | public: 10 | static bool isImportedFunction(PEFile *m_PE, offset_t offset, Executable::addr_type aType) 11 | { 12 | if (!m_PE) return false; 13 | if (offset == INVALID_ADDR) return false; 14 | Executable::addr_type detectedType = m_PE->detectAddrType(offset, aType); 15 | offset_t rva = m_PE->convertAddr(offset, detectedType, Executable::RVA); 16 | 17 | ImportDirWrapper *imports = m_PE->getImports(); 18 | if (imports) { 19 | if (imports->hasThunk(rva)) return true; 20 | } 21 | DelayImpDirWrapper* delayedImps = m_PE->getDelayedImports(); 22 | if (delayedImps) { 23 | 24 | 25 | if (delayedImps->hasThunk(rva)) { 26 | //printf("IN Delayed imports!\n"); 27 | return true; 28 | } 29 | offset_t va = m_PE->convertAddr(offset, detectedType, Executable::VA); 30 | if (delayedImps->hasThunk(va)) { 31 | //printf("IN Delayed imports!\n"); 32 | return true; 33 | } 34 | } 35 | return false; 36 | } 37 | 38 | static QString getImportName(PEFile *m_PE, offset_t offset, Executable::addr_type aType) 39 | { 40 | if (!m_PE) return ""; 41 | if (offset == INVALID_ADDR) return ""; 42 | Executable::addr_type detectedType = m_PE->detectAddrType(offset, aType); 43 | offset_t rva = m_PE->convertAddr(offset, detectedType, Executable::RVA); 44 | 45 | ImportDirWrapper *imports = m_PE->getImports(); 46 | if (imports) { 47 | if (imports->hasThunk(rva)) { 48 | return imports->thunkToLibName(rva) + "." + imports->thunkToFuncName(rva); 49 | } 50 | } 51 | DelayImpDirWrapper* delayedImps = m_PE->getDelayedImports(); 52 | if (delayedImps) { 53 | if (delayedImps->hasThunk(rva)) { 54 | return delayedImps->thunkToLibName(rva) + ":" + delayedImps->thunkToFuncName(rva); 55 | } 56 | offset_t va = m_PE->convertAddr(offset, detectedType, Executable::VA); 57 | if (delayedImps->hasThunk(va)) { 58 | return delayedImps->thunkToLibName(va) + ":" + delayedImps->thunkToFuncName(va); 59 | } 60 | } 61 | return "?"; 62 | } 63 | 64 | }; 65 | }; /* namespace minidis */ 66 | -------------------------------------------------------------------------------- /disasm/include/pe/PeDisasm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../ExeDisasm.h" 4 | #include "PeDataFetcher.h" 5 | 6 | #define PREVIEW_SIZE 0x200 7 | 8 | namespace minidis { 9 | 10 | class PeDisasm : public ExeDisasm 11 | { 12 | 13 | public: 14 | PeDisasm(PEFile *pe); 15 | 16 | bool init(offset_t startOffset) 17 | { 18 | bufsize_t disasmSize = m_PE->getContentSize() - startOffset; 19 | 20 | SectionHdrWrapper* hdr = this->m_PE->getSecHdrAtOffset(startOffset, Executable::RAW, false); 21 | if (hdr) { 22 | offset_t start = startOffset - hdr->getContentOffset(Executable::RAW); 23 | bufsize_t secSize = hdr->getContentSize(Executable::RAW, false); 24 | disasmSize = secSize - start; 25 | } 26 | return ExeDisasm::init(startOffset, disasmSize); 27 | } 28 | 29 | bool fillTable(const DisasmSettings& settings); 30 | 31 | virtual bool isImportedFunction(offset_t offset, Executable::addr_type aType) const 32 | { 33 | return PeDataFetcher::isImportedFunction(m_PE, offset, aType); 34 | } 35 | 36 | virtual QString getImportName(offset_t offset, Executable::addr_type aType) const 37 | { 38 | return PeDataFetcher::getImportName(m_PE, offset, aType); 39 | } 40 | 41 | virtual bool isImportCall(size_t index) 42 | { 43 | offset_t target = getTargetOffset(index, Executable::RVA); 44 | if (target != INVALID_ADDR && this->isImportedFunction(target, Executable::RVA)) { 45 | return true; 46 | } 47 | return false; 48 | } 49 | 50 | protected: 51 | offset_t getRawAt(const size_t index) const; 52 | 53 | PEFile *m_PE; 54 | 55 | }; /* class PeDisasm */ 56 | 57 | }; /* namespace minidis */ 58 | 59 | -------------------------------------------------------------------------------- /disasm/include/pe/PeTracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Tracer.h" 7 | #include "PeDisasm.h" 8 | 9 | namespace minidis { 10 | 11 | class PeTracer : public Tracer, protected PeDataFetcher 12 | { 13 | public: 14 | PeTracer(PEFile *exe) 15 | : Tracer(exe) , m_PE(exe){ } 16 | 17 | void traceEntrySection(); 18 | bool traceFunction(offset_t offset, Executable::addr_type aType, QString name); 19 | 20 | virtual bool isImportedFunction(offset_t offset, Executable::addr_type aType) const 21 | { 22 | return PeDataFetcher::isImportedFunction(m_PE, offset, aType); 23 | } 24 | 25 | virtual QString getImportName(offset_t offset, Executable::addr_type aType) const 26 | { 27 | return PeDataFetcher::getImportName(m_PE, offset, aType); 28 | } 29 | 30 | protected: 31 | 32 | size_t findAllPrologs(QSet &prologOffsets); 33 | virtual PeDisasm* makeDisasm(Executable* exe, offset_t startRaw); 34 | 35 | PEFile *m_PE; 36 | }; 37 | 38 | }; /* namespace minidis */ 39 | -------------------------------------------------------------------------------- /disasm/pe/PeDisasm.cpp: -------------------------------------------------------------------------------- 1 | #include "pe/PeDisasm.h" 2 | 3 | using namespace minidis; 4 | 5 | PeDisasm::PeDisasm(PEFile *pe) 6 | : ExeDisasm(pe, 0), m_PE(pe) 7 | { 8 | if (pe == NULL) throw CustomException("PE not initialized!"); 9 | } 10 | 11 | bool PeDisasm::fillTable(const DisasmSettings& settings) 12 | { 13 | return ExeDisasm::fillTable(settings); 14 | } 15 | -------------------------------------------------------------------------------- /disasm/pe/PeTracer.cpp: -------------------------------------------------------------------------------- 1 | #include "pe/PeTracer.h" 2 | #include "../Util.h" 3 | 4 | using namespace minidis; 5 | 6 | //---- 7 | class Pattern { 8 | public: 9 | Pattern() 10 | : buf(NULL), size(0) 11 | { 12 | } 13 | 14 | Pattern(BYTE *bufPtr, size_t bufSize) 15 | { 16 | this->buf = bufPtr; 17 | this->size = bufSize; 18 | } 19 | 20 | BYTE* buf; 21 | size_t size; 22 | }; 23 | 24 | //---- 25 | //protected: 26 | size_t PeTracer::findAllPrologs(QSet &prologOffsets) 27 | { 28 | size_t initialSize = prologOffsets.size(); 29 | 30 | const offset_t epRaw = m_PE->getEntryPoint(Executable::RAW); 31 | SectionHdrWrapper *hdr = m_PE->getSecHdrAtOffset(epRaw, Executable::RAW, false); 32 | if (!hdr) return 0; 33 | 34 | const offset_t secStart = hdr->getContentOffset(Executable::RAW, false); 35 | const bufsize_t secSize = hdr->getContentSize(Executable::RAW, false); 36 | 37 | BYTE *secPtr = m_PE->getContentAt(secStart, secSize); 38 | if (!secPtr) { 39 | return 0; 40 | } 41 | BYTE prolog32_pattern[] = { 42 | 0x55, // PUSH EBP 43 | 0x8b, 0xEC // MOV EBP, ESP 44 | }; 45 | 46 | BYTE prolog32_2_pattern[] = { 47 | 0x55, // PUSH EBP 48 | 0x89, 0xE5 // MOV EBP, ESP 49 | }; 50 | 51 | BYTE prolog64_pattern_0[] = { 52 | 0x55, // PUSH RBP 53 | 0x48, 0x8b, 0xEC // MOV RBP, RSP 54 | }; 55 | 56 | BYTE prolog64_pattern_1[] = { 57 | 0x40, 0x53, // PUSH RBX 58 | 0x48, 0x83, 0xEC // SUB RSP, ?? 59 | }; 60 | 61 | BYTE prolog64_pattern_2[] = { 62 | 0x40, 0x55, // PUSH ?? 63 | 0x48, 0x83, 0xEC // SUB RSP, ?? 64 | }; 65 | 66 | BYTE prolog64_pattern_3[] = { 67 | 0x48, 0x83, 0xEC // SUB RSP, ?? 68 | }; 69 | //TODO: make a pattern covering all the cases 70 | QVector patterns; 71 | patterns.push_back(Pattern(prolog32_pattern, sizeof(prolog32_pattern))); 72 | patterns.push_back(Pattern(prolog32_2_pattern, sizeof(prolog32_2_pattern))); 73 | if (m_PE->isBit64()) { 74 | patterns.push_back(Pattern(prolog64_pattern_0, sizeof(prolog64_pattern_0))); 75 | patterns.push_back(Pattern(prolog64_pattern_1, sizeof(prolog64_pattern_1))); 76 | patterns.push_back(Pattern(prolog64_pattern_2, sizeof(prolog64_pattern_2))); 77 | patterns.push_back(Pattern(prolog64_pattern_3, sizeof(prolog64_pattern_3))); 78 | } 79 | BYTE *nextPtr = secPtr; 80 | size_t nextSize = secSize; 81 | 82 | BYTE hotpatch_buf[] = { 0x8b, 0xff }; //mov edi, edi 83 | Pattern hotpatch(hotpatch_buf, sizeof(hotpatch_buf)); 84 | 85 | for (nextPtr = secPtr; nextPtr < (secPtr + secSize);) { 86 | if (!nextPtr) break; 87 | 88 | size_t nextSize = secSize - (nextPtr - secPtr); 89 | BYTE *patternPtr = NULL; 90 | size_t patternSize = 0; 91 | 92 | //search by stored patterns: 93 | for (int i = 0; i < patterns.size(); i++) { 94 | patternPtr = find_pattern(nextPtr, nextSize, patterns.at(i).buf, patterns.at(i).size); 95 | if (!patternPtr) { 96 | //try with another pattern 97 | continue; 98 | } 99 | //pattern found! 100 | patternSize = patterns.at(i).size; 101 | //check for eventual hotpatch prolog: 102 | if ((patternPtr - secPtr) >= hotpatch.size) { 103 | BYTE *hotPatchPtr = patternPtr - hotpatch.size; 104 | if (memcmp(hotPatchPtr, hotpatch.buf, hotpatch.size) == 0) { 105 | patternPtr = hotPatchPtr; 106 | patternSize += hotpatch.size; 107 | } 108 | } 109 | //advance the search: 110 | nextPtr = patternPtr + patternSize; 111 | 112 | offset_t offset1 = m_PE->getOffset(patternPtr); 113 | if (offset1 != INVALID_ADDR) { 114 | prologOffsets.insert(offset1); 115 | break; 116 | } 117 | } 118 | //none of the pattern was found, break: 119 | if (!patternPtr || !patternSize) break; 120 | 121 | //otherwise search for the next occurence... 122 | } 123 | return prologOffsets.size() - initialSize; 124 | } 125 | 126 | void PeTracer::traceEntrySection() 127 | { 128 | const offset_t epRaw = m_PE->getEntryPoint(Executable::RAW); 129 | SectionHdrWrapper *hdr = m_PE->getSecHdrAtOffset(epRaw, Executable::RAW, false); 130 | if (!hdr) return; 131 | 132 | const offset_t secStart = hdr->getContentOffset(Executable::RAW, false); 133 | makeDisasmAt(m_Exe, secStart, sectionTraceSettings); 134 | traceArea(secStart); 135 | } 136 | 137 | bool PeTracer::traceFunction(offset_t offset, Executable::addr_type aType, QString name) 138 | { 139 | const offset_t start = this->convertAddr(offset, aType, Executable::RAW); 140 | if (start == INVALID_ADDR) return false; 141 | 142 | if (!makeDisasmAt(m_Exe, start, this->functionTraceSettings)) { 143 | return false; 144 | } 145 | traceArea(start); 146 | return defineFunction(offset, aType, name); 147 | } 148 | 149 | PeDisasm* PeTracer::makeDisasm(Executable* exe, offset_t startRaw) 150 | { 151 | PEFile *pe = dynamic_cast(exe); 152 | if (!pe) return NULL; 153 | PeDisasm *disasm = new PeDisasm(pe); 154 | if (!disasm->init(startRaw)) { 155 | delete disasm; 156 | disasm = NULL; 157 | } 158 | return disasm; 159 | } 160 | -------------------------------------------------------------------------------- /disasm/udis/ExeDisasm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include "udis/UDisasm.h" 4 | #include "UDisasm.h" 5 | 6 | namespace minidis { 7 | 8 | class ExeDisasm : public UDisasm { 9 | public: 10 | ExeDisasm(Executable *exe, offset_t startOffset) : UDisasm(exe, startOffset) {} 11 | 12 | virtual bool init(const offset_t startOffset, const bufsize_t disasmSize) 13 | { 14 | return UDisasm::init(startOffset, disasmSize, m_Exe->getBitMode()); 15 | } 16 | 17 | virtual QString getImportName(offset_t offset, Executable::addr_type aType) const = 0; 18 | virtual bool isImportedFunction(offset_t offset, Executable::addr_type aType) const = 0; 19 | 20 | virtual bool isFollowable(const size_t index) const 21 | { 22 | return UDisasm::isFollowable(index); 23 | } 24 | 25 | bool isBranching(size_t index) 26 | { 27 | mnem_type mType = this->getMnemTypeAtIndex(index); 28 | return UDisasm::isBranching(mType); 29 | } 30 | 31 | bool isBranching(offset_t offset, Executable::addr_type aType) 32 | { 33 | size_t index = this->offsetToIndex(offset, aType); 34 | if (index == INVALID_INDEX) return false; 35 | 36 | mnem_type mType = this->getMnemTypeAtIndex(index); 37 | return UDisasm::isBranching(mType); 38 | } 39 | 40 | bool isFollowable(size_t index) 41 | { 42 | return UDisasm::isFollowable(index); 43 | } 44 | 45 | bool isFollowable(offset_t offset, Executable::addr_type aType) 46 | { 47 | size_t index = this->offsetToIndex(offset, aType); 48 | if (index == INVALID_INDEX) return false; 49 | 50 | return UDisasm::isFollowable(index); 51 | } 52 | }; 53 | 54 | }; /* namespace minidis */ 55 | -------------------------------------------------------------------------------- /disasm/udis/UDisasm.cpp: -------------------------------------------------------------------------------- 1 | #include "UDisasm.h" 2 | 3 | using namespace minidis; 4 | 5 | bool UDisasm::init(offset_t raw, bufsize_t disasmSize, Executable::exe_bits bitMode) 6 | { 7 | m_startOffset = raw; 8 | m_bitMode = bitMode; 9 | m_disasmBuf.clear(); 10 | 11 | //printf("UDisasm::init : Init buffer at offset %lx bit mode: %d\n", m_startOffset, m_bitMode); 12 | m_buf = m_Exe->getContentAt(m_startOffset, Executable::RAW); 13 | m_bufSize = m_Exe->getContentSize() - m_startOffset; 14 | if (m_buf == NULL || m_bufSize == 0) return false; 15 | 16 | m_iptr = 0; 17 | 18 | m_disasmSize = m_bufSize < disasmSize ? m_bufSize : disasmSize; 19 | m_disasmBuf.setStartOffset(m_startOffset); 20 | 21 | ud_init(&this->ud_obj); 22 | ud_set_input_buffer(&this->ud_obj, m_buf, m_disasmSize); 23 | ud_set_mode(&this->ud_obj, static_cast(m_bitMode)); 24 | ud_set_syntax(&ud_obj, UD_SYN_INTEL); 25 | 26 | this->is_init = true; 27 | return true; 28 | } 29 | 30 | size_t UDisasm::disasmNext() 31 | { 32 | if (!is_init) { 33 | printf("Cannot disasm next = NOT INIT!\n"); 34 | return 0; 35 | } 36 | if (!ud_disassemble(&this->ud_obj)) { 37 | is_init = false; 38 | return 0; 39 | } 40 | size_t step = ud_insn_len(&this->ud_obj); 41 | m_iptr += step; 42 | return step; 43 | } 44 | 45 | DisasmChunk* UDisasm::makeChunk(offset_t startRVA) 46 | { 47 | return new UdisChunk(ud_obj, startRVA, m_Exe); 48 | } 49 | 50 | /* TODO: test it!!! */ 51 | int64_t UDisasm::getSignedLVal(const ud_t &inpObj, size_t argNum, bool &isOk) const 52 | { 53 | if (argNum > MAX_ARG_NUM) return INVALID_ADDR; 54 | isOk = false; 55 | int64_t lValue = 0; 56 | uint8_t size = inpObj.operand[argNum].size; 57 | 58 | if (size == 0) return 0; 59 | uint8_t maxSize = sizeof(uint64_t) * 8; // in bits 60 | uint8_t dif = maxSize - size; 61 | 62 | lValue = inpObj.operand[argNum].lval.uqword; 63 | int64_t mlValue = (lValue << dif) >> dif; // gives signed!!! 64 | isOk = true; 65 | return mlValue; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /disasm/udis/UDisasm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../DisasmBase.h" 5 | 6 | #include "UdisChunk.h" 7 | 8 | namespace minidis { 9 | //------------------------------------------------ 10 | 11 | /* abstract class, base of all the Disasms*/ 12 | class UDisasm : public DisasmBase 13 | { 14 | public: 15 | 16 | /* non-static */ 17 | UDisasm(Executable* exe, offset_t startOffset) 18 | : DisasmBase(exe, startOffset) 19 | { 20 | //init(); 21 | } 22 | 23 | bool init(offset_t rva, bufsize_t disasmSize, Executable::exe_bits bitMode); 24 | 25 | protected: 26 | 27 | virtual DisasmChunk* makeChunk(offset_t startRVA); 28 | 29 | static uint64_t trimToBitMode(int64_t value, Executable::exe_bits bits); 30 | //--- 31 | virtual size_t disasmNext(); 32 | int64_t getSignedLVal(const ud_t &obj, size_t operandNum, bool &isOk) const; /* TODO: test it!!! */ 33 | 34 | private: 35 | 36 | BYTE *m_buf; 37 | bufsize_t m_bufSize; 38 | bufsize_t m_disasmSize; 39 | 40 | offset_t m_iptr; //instruction pointer 41 | ud_t ud_obj; 42 | 43 | }; /* class DisasmBase */ 44 | 45 | }; /* namespace minidis */ 46 | -------------------------------------------------------------------------------- /disasm/udis/UdisChunk.cpp: -------------------------------------------------------------------------------- 1 | #include "UdisChunk.h" 2 | 3 | using namespace minidis; 4 | 5 | #define MAX_ARG_NUM 4 6 | 7 | bool UdisChunk::fetchTargetAddr(const size_t argNum, TargetValue &targetVal) const 8 | { 9 | size_t cnt = MAX_ARG_NUM; 10 | if (argNum >= cnt) return false; 11 | targetVal.m_targetOpNum = argNum; 12 | 13 | const ud_t &inpObj = this->ud_obj; 14 | 15 | bool got = false; 16 | offset_t lval = getSignedLVal(inpObj, argNum, got); 17 | if (!got) return INVALID_ADDR; 18 | 19 | const ud_type opType = inpObj.operand[argNum].type; 20 | const ud_type regType = inpObj.operand[argNum].base; 21 | 22 | const offset_t currIP = this->m_startOffset + this->getOffset() + this->getChunkSize(); 23 | 24 | if (opType == UD_OP_JIMM) { 25 | setTargetVal(targetVal, argNum, Executable::RVA, currIP + lval, true); 26 | return true; 27 | } 28 | if (opType == UD_OP_IMM) { 29 | setTargetVal(targetVal, argNum, Executable::VA, lval, true); 30 | return true; 31 | } 32 | 33 | if (opType == UD_OP_MEM) { 34 | if (regType == UD_NONE) { // may be VA 35 | setTargetVal(targetVal, argNum, Executable::VA, lval, true); 36 | return true; 37 | } 38 | 39 | if (regType == UD_R_RIP) { 40 | setTargetVal(targetVal, argNum, Executable::RVA, currIP + lval, true); 41 | return true; 42 | } 43 | } 44 | return false; 45 | } 46 | 47 | TargetValue UdisChunk::fetchTargetAddr() 48 | { 49 | TargetValue targetVal; 50 | targetVal.setValues(0, Executable::NOT_ADDR, INVALID_ADDR, INVALID_ADDR); 51 | 52 | const size_t cnt = getMaxArg(); 53 | if (cnt == 0) return targetVal; 54 | 55 | for (size_t i = 0; i < cnt; i++) { 56 | 57 | bool isOk = fetchTargetAddr(i, targetVal); 58 | if (!isOk || targetVal.getAddrType() == Executable::NOT_ADDR) continue; 59 | // OK: 60 | return targetVal; 61 | } 62 | targetVal.setValues(0, Executable::NOT_ADDR, INVALID_ADDR, INVALID_ADDR); 63 | return targetVal; 64 | } 65 | 66 | //public: 67 | int64_t UdisChunk::getSignedLVal(const ud_t &inpObj, size_t argNum, bool &isOk) 68 | { 69 | isOk = false; 70 | if (argNum > MAX_ARG_NUM) return INVALID_ADDR; 71 | 72 | int64_t lValue = 0; 73 | uint8_t size = inpObj.operand[argNum].size; 74 | if (size == 0) return 0; 75 | 76 | uint8_t maxSize = sizeof(uint64_t) * 8; // in bits 77 | uint8_t dif = maxSize - size; 78 | 79 | lValue = inpObj.operand[argNum].lval.uqword; 80 | int64_t mlValue = (lValue << dif) >> dif; // gives signed!!! 81 | isOk = true; 82 | return mlValue; 83 | } 84 | 85 | //--- 86 | 87 | mnem_type UdisChunk::fetchMnemType() const 88 | { 89 | switch(ud_obj.mnemonic) 90 | { 91 | case UD_Ijo : case UD_Ijno : case UD_Ijb : case UD_Ijae : 92 | case UD_Ijz : case UD_Ijnz : case UD_Ijbe : case UD_Ija : 93 | case UD_Ijs : case UD_Ijns : case UD_Ijp : case UD_Ijnp : 94 | case UD_Ijl : case UD_Ijge : case UD_Ijle : case UD_Ijg : 95 | case UD_Ijcxz : case UD_Ijecxz : case UD_Ijrcxz : 96 | return MT_COND_JUMP; 97 | 98 | case UD_Ijmp : 99 | return MT_JUMP; 100 | 101 | case UD_Iloop: return MT_LOOP; 102 | case UD_Icall : return MT_CALL; 103 | 104 | case UD_Iret: 105 | case UD_Iretf : 106 | return MT_RET; 107 | 108 | case UD_Inop : return MT_NOP; 109 | case UD_Iinvalid : 110 | return MT_INVALID; 111 | 112 | case UD_Ipush : 113 | case UD_Ipusha: 114 | case UD_Ipushad: 115 | case UD_Ipushfd: 116 | case UD_Ipushfq: 117 | case UD_Ipushfw: 118 | return MT_PUSH; 119 | 120 | case UD_Ipop : 121 | case UD_Ipopa: 122 | case UD_Ipopad: 123 | case UD_Ipopcnt: 124 | case UD_Ipopfd: 125 | case UD_Ipopfq: 126 | case UD_Ipopfw: 127 | return MT_POP; 128 | 129 | case UD_Iint3 : 130 | return MT_INT3; 131 | 132 | case UD_Iint: 133 | return MT_INTX; 134 | } 135 | return MT_OTHER; 136 | } 137 | 138 | QString UdisChunk::translateBranchingMnemonic() const 139 | { 140 | ud_mnemonic_code_t mnem = ud_obj.mnemonic; 141 | QString mnemDesc = ""; 142 | switch (mnem) { 143 | case UD_Iloop: mnemDesc = "LOOP"; break; 144 | case UD_Ijo : mnemDesc = "JO"; break; 145 | case UD_Ijno : mnemDesc = "JNO"; break; 146 | case UD_Ijb : mnemDesc = "JB"; break; 147 | case UD_Ijae : mnemDesc = "JLAE"; break; 148 | case UD_Ijz : mnemDesc = "JZ"; break; 149 | case UD_Ijnz : mnemDesc = "JNZ"; break; 150 | case UD_Ijbe : mnemDesc = "JBE"; break; 151 | case UD_Ija : mnemDesc = "JA"; break; 152 | case UD_Ijs : mnemDesc = "JS"; break; 153 | case UD_Ijns : mnemDesc = "JNS"; break; 154 | case UD_Ijp : mnemDesc = "JP"; break; 155 | case UD_Ijnp : mnemDesc = "JNP"; break; 156 | case UD_Ijl : mnemDesc = "JL"; break; 157 | case UD_Ijge : mnemDesc = "JGE"; break; 158 | case UD_Ijle : mnemDesc = "JLE"; break; 159 | case UD_Ijg : mnemDesc = "JG"; break; 160 | case UD_Ijcxz : mnemDesc = "JCXZ"; break; 161 | case UD_Ijecxz : mnemDesc = "JECXZ"; break; 162 | case UD_Ijrcxz : mnemDesc = "JRCXZ"; break; 163 | case UD_Ijmp : mnemDesc = "JMP"; break; 164 | case UD_Icall : mnemDesc = "CALL"; break; 165 | } 166 | return mnemDesc; 167 | } 168 | 169 | bool UdisChunk::isAddrOperand() const 170 | { 171 | if (ud_obj.mnemonic == UD_Ipush || ud_obj.mnemonic == UD_Imov) return true; 172 | 173 | for (int i = 0 ; i < MAX_ARG_NUM; i++) { 174 | if (ud_obj.operand[i].type == UD_OP_IMM && 175 | ud_obj.operand[i].size > 8) 176 | { 177 | return true; 178 | } 179 | } 180 | return false; 181 | } 182 | 183 | -------------------------------------------------------------------------------- /disasm/udis/UdisChunk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../DisasmChunk.h" 7 | 8 | namespace minidis { 9 | 10 | class UdisChunk : public DisasmChunk 11 | { 12 | public: 13 | UdisChunk(ud_t udObj, offset_t startOffset,Executable *parent) 14 | : ud_obj(udObj), DisasmChunk(startOffset, parent) 15 | { 16 | m_mnemType = fetchMnemType(); 17 | m_targetVal = fetchTargetAddr(); 18 | } 19 | 20 | virtual bufsize_t getChunkSize() const { return ud_insn_len(&ud_obj); } 21 | 22 | virtual QString translateBranchingMnemonic() const; 23 | virtual bool isAddrOperand() const; 24 | 25 | protected: 26 | virtual void initStrings() 27 | { 28 | m_disasmString = QString(ud_obj.asm_buf_int); 29 | m_hexStr = QString::fromAscii(ud_insn_hex(&ud_obj)).toUpper(); 30 | } 31 | 32 | virtual mnem_type fetchMnemType() const; 33 | virtual size_t getMaxArg() { return MAX_ARG_NUM; } 34 | 35 | virtual offset_t getOffset() const { return ud_insn_off(&ud_obj); } 36 | 37 | private: 38 | bool fetchTargetAddr(const size_t argNum, TargetValue &targetVal) const; 39 | TargetValue fetchTargetAddr(); 40 | static int64_t getSignedLVal(const ud_t &inpObj, size_t argNum, bool &isOk); 41 | ud_t ud_obj; 42 | 43 | friend class UDisasm; 44 | }; 45 | 46 | }; // namespace minidis 47 | --------------------------------------------------------------------------------