diff options
author | Samuel Lidén Borell <samuel@kodafritt.se> | 2015-01-04 02:26:24 +0100 |
---|---|---|
committer | Samuel Lidén Borell <samuel@kodafritt.se> | 2015-01-04 02:26:24 +0100 |
commit | e4365529a111f8cbfc5950808c35b5951f66da8e (patch) | |
tree | bcba75f5edc77b613b0266067b6a42b4e295d40c | |
download | LoopyTrace-main.tar.gz LoopyTrace-main.tar.bz2 LoopyTrace-main.zip |
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | HitTrace/HitTrace.dev | 98 | ||||
-rw-r--r-- | HitTrace/HitTrace.exe.Manifest | 23 | ||||
-rw-r--r-- | HitTrace/HitTrace.ico | bin | 0 -> 1078 bytes | |||
-rw-r--r-- | HitTrace/HitTrace_private.h | 23 | ||||
-rw-r--r-- | HitTrace/HitTrace_private.rc | 45 | ||||
-rw-r--r-- | HitTrace/License.txt | 19 | ||||
-rw-r--r-- | HitTrace/Makefile.win | 36 | ||||
-rw-r--r-- | HitTrace/Readme.txt | 22 | ||||
-rw-r--r-- | HitTrace/main.c | 971 | ||||
-rw-r--r-- | HitTrace/main.rc | 69 | ||||
-rw-r--r-- | HitTrace/resource.h | 56 | ||||
-rw-r--r-- | HitTrace/x86ops.c | 754 | ||||
-rw-r--r-- | HitTrace/x86ops.h | 30 |
14 files changed, 2149 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41b749b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.exe +*.res diff --git a/HitTrace/HitTrace.dev b/HitTrace/HitTrace.dev new file mode 100644 index 0000000..d21f0ae --- /dev/null +++ b/HitTrace/HitTrace.dev @@ -0,0 +1,98 @@ +[Project]
+FileName=HitTrace.dev
+Name=HitTrace
+UnitCount=5
+Type=0
+Ver=1
+ObjFiles=
+Includes=
+Libs=
+PrivateResource=HitTrace_private.rc
+ResourceIncludes=
+MakeIncludes=
+Compiler=-D_WIN32_WINDOWS=0x0490_@@_
+CppCompiler=
+Linker=-lcomctl32_@@_
+IsCpp=0
+Icon=HitTrace.ico
+ExeOutput=
+ObjectOutput=
+OverrideOutput=0
+OverrideOutputName=HitTrace.exe
+HostApplication=
+Folders=
+CommandLine=
+UseCustomMakefile=0
+CustomMakefile=
+IncludeVersionInfo=1
+SupportXPThemes=1
+CompilerSet=0
+CompilerSettings=0000000000000000000000
+
+[Unit1]
+FileName=main.c
+CompileCpp=0
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[VersionInfo]
+Major=0
+Minor=1
+Release=0
+Build=0
+LanguageID=1033
+CharsetID=1252
+CompanyName=
+FileVersion=
+FileDescription=HitTrace, part of LoopyTrace
+InternalName=
+LegalCopyright=Copyright (C) 2014-2015 Samuel Lidén Borell
+LegalTrademarks=
+OriginalFilename=HitTrace.exe
+ProductName=HitTrace, part of LoopyTrace
+ProductVersion=0.1.0.0
+AutoIncBuildNr=0
+
+[Unit2]
+FileName=main.rc
+Folder=HitTrace
+Compile=1
+Link=0
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit3]
+FileName=resource.h
+CompileCpp=0
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit4]
+FileName=x86ops.h
+CompileCpp=0
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit5]
+FileName=x86ops.c
+CompileCpp=0
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
diff --git a/HitTrace/HitTrace.exe.Manifest b/HitTrace/HitTrace.exe.Manifest new file mode 100644 index 0000000..5286f28 --- /dev/null +++ b/HitTrace/HitTrace.exe.Manifest @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly
+ xmlns="urn:schemas-microsoft-com:asm.v1"
+ manifestVersion="1.0">
+<assemblyIdentity
+ name="DevCpp.Apps.HitTrace"
+ processorArchitecture="x86"
+ version="1.0.0.0"
+ type="win32"/>
+<description>HitTrace</description>
+<dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ processorArchitecture="x86"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+</dependency>
+</assembly>
diff --git a/HitTrace/HitTrace.ico b/HitTrace/HitTrace.ico Binary files differnew file mode 100644 index 0000000..ba58684 --- /dev/null +++ b/HitTrace/HitTrace.ico diff --git a/HitTrace/HitTrace_private.h b/HitTrace/HitTrace_private.h new file mode 100644 index 0000000..9660d20 --- /dev/null +++ b/HitTrace/HitTrace_private.h @@ -0,0 +1,23 @@ +/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */
+/* DO NOT EDIT ! */
+
+#ifndef HITTRACE_PRIVATE_H
+#define HITTRACE_PRIVATE_H
+
+/* VERSION DEFINITIONS */
+#define VER_STRING "0.1.0.0"
+#define VER_MAJOR 0
+#define VER_MINOR 1
+#define VER_RELEASE 0
+#define VER_BUILD 0
+#define COMPANY_NAME ""
+#define FILE_VERSION ""
+#define FILE_DESCRIPTION "HitTrace, part of LoopyTrace"
+#define INTERNAL_NAME ""
+#define LEGAL_COPYRIGHT "Copyright (C) 2014-2015 Samuel Lidén Borell"
+#define LEGAL_TRADEMARKS ""
+#define ORIGINAL_FILENAME "HitTrace.exe"
+#define PRODUCT_NAME "HitTrace, part of LoopyTrace"
+#define PRODUCT_VERSION "0.1.0.0"
+
+#endif /*HITTRACE_PRIVATE_H*/
diff --git a/HitTrace/HitTrace_private.rc b/HitTrace/HitTrace_private.rc new file mode 100644 index 0000000..1b2446a --- /dev/null +++ b/HitTrace/HitTrace_private.rc @@ -0,0 +1,45 @@ +/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */
+/* DO NOT EDIT! */
+
+#include <windows.h> // include for version info constants
+
+#include "main.rc"
+
+A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "HitTrace.ico"
+
+//
+// SUPPORT FOR WINDOWS XP THEMES:
+// THIS WILL MAKE THE PROGRAM USE THE COMMON CONTROLS
+// LIBRARY VERSION 6.0 (IF IT IS AVAILABLE)
+//
+1 24 "HitTrace.exe.Manifest"
+
+//
+// TO CHANGE VERSION INFORMATION, EDIT PROJECT OPTIONS...
+//
+1 VERSIONINFO
+FILEVERSION 0,1,0,0
+PRODUCTVERSION 0,1,0,0
+FILETYPE VFT_APP
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904E4"
+ {
+ VALUE "CompanyName", ""
+ VALUE "FileVersion", ""
+ VALUE "FileDescription", "HitTrace, part of LoopyTrace"
+ VALUE "InternalName", ""
+ VALUE "LegalCopyright", "Copyright (C) 2014-2015 Samuel Lidén Borell"
+ VALUE "LegalTrademarks", ""
+ VALUE "OriginalFilename", "HitTrace.exe"
+ VALUE "ProductName", "HitTrace, part of LoopyTrace"
+ VALUE "ProductVersion", "0.1.0.0"
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 1252
+ }
+}
+
diff --git a/HitTrace/License.txt b/HitTrace/License.txt new file mode 100644 index 0000000..3bfa0e3 --- /dev/null +++ b/HitTrace/License.txt @@ -0,0 +1,19 @@ +Copyright (c) 2014-2015 Samuel Lidén Borell <samuel@kodafritt.se>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file diff --git a/HitTrace/Makefile.win b/HitTrace/Makefile.win new file mode 100644 index 0000000..6260373 --- /dev/null +++ b/HitTrace/Makefile.win @@ -0,0 +1,36 @@ +# Project: HitTrace
+# Makefile created by Dev-C++ 4.9.9.2
+
+CPP = g++.exe
+CC = gcc.exe
+WINDRES = windres.exe
+RES = HitTrace_private.res
+OBJ = main.o x86ops.o $(RES)
+LINKOBJ = main.o x86ops.o $(RES)
+LIBS = -L"C:/Dev-Cpp/lib" -mwindows -lcomctl32
+INCS = -I"C:/Dev-Cpp/include"
+CXXINCS = -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include"
+BIN = HitTrace.exe
+CXXFLAGS = $(CXXINCS)
+CFLAGS = $(INCS) -D_WIN32_WINDOWS=0x0490
+RM = rm -f
+
+.PHONY: all all-before all-after clean clean-custom
+
+all: all-before HitTrace.exe all-after
+
+
+clean: clean-custom
+ ${RM} $(OBJ) $(BIN)
+
+$(BIN): $(OBJ)
+ $(CC) $(LINKOBJ) -o "HitTrace.exe" $(LIBS)
+
+main.o: main.c
+ $(CC) -c main.c -o main.o $(CFLAGS)
+
+x86ops.o: x86ops.c
+ $(CC) -c x86ops.c -o x86ops.o $(CFLAGS)
+
+HitTrace_private.res: HitTrace_private.rc main.rc
+ $(WINDRES) -i HitTrace_private.rc --input-format=rc -o HitTrace_private.res -O coff
diff --git a/HitTrace/Readme.txt b/HitTrace/Readme.txt new file mode 100644 index 0000000..2644fcd --- /dev/null +++ b/HitTrace/Readme.txt @@ -0,0 +1,22 @@ +LoopyTrace HitTrace
+===================
+
+This is a simple hit tracer, that instead of using breakpoints overwrites
+instructions to be traced with an infinite loop to "trap" the execution
+at the traced location. HitTrace then monitors the instruction pointers
+of the traced process' threads, to see if any of the threads have been
+"trapped" in one of the infinite loops. If so we have a "hit".
+
+The advantage of this technique is that most types of anti-debug tricks
+do not detect it. However, it will not work with program that use
+checksumming or polymorhphic code.
+
+Only the very first instruction of functions are traced. Functions are
+searched for using a heuristic, which is not 100% accurate for all
+programs and may cause crashes or instability (for instance some types of
+jump tables can be incorrectly matched as functions and corrupted).
+Also, HitTrace will only trace the first code section.
+
+The reached memory regions is displayed in real time, and a full dump
+of all reached functions can be saved in PE (.exe) format. Code that
+was not reached is replaced with NOP (0x90) instructions.
diff --git a/HitTrace/main.c b/HitTrace/main.c new file mode 100644 index 0000000..8d71165 --- /dev/null +++ b/HitTrace/main.c @@ -0,0 +1,971 @@ +/*
+
+ Copyright (c) 2014-2015 Samuel Lidén Borell <samuel@kodafritt.se>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+*/
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <TlHelp32.h>
+
+#include "resource.h"
+#include "x86ops.h"
+
+
+#define HIT_PATCHED 0x1 /* Patched initially (but maybe unpatched later) */
+#define HIT_REACHED 0x2 /* Reached (and unpatched) */
+#define HIT_IGNORED 0x4 /* Ignored by user */
+typedef struct SectionInfo {
+ struct SectionInfo* next;
+
+ DWORD va_start;
+ DWORD va_size;
+
+ BYTE *orig; /* copy of original code section contents */
+ BYTE *hits; /* patched and/or reached */
+} SectionInfo;
+
+typedef enum {
+ /* Granularity */
+ TRC_CALL, /* Functions Inject a function and overwrite all function prologues with a CALL */
+ TRC_INT3, /* Instructions Inject an exception handler and replace all instructions with INT3 */
+ TRC_LOOP, /* Functions Overwrite all function prologues with a JMP -2, and wait for the program to reach there */
+ TRC_NX /* Pages Inject an exception handler and mark all pages as non-executable. */
+ /* (only LOOP tracing is implemented) */
+} TraceMode;
+
+/* NT internal stuff */
+#define ProcessBasicInformation 0
+typedef struct {
+ PVOID Reserved1;
+ /*PPEB*/PVOID PebBaseAddress;
+ PVOID Reserved2[2];
+ ULONG_PTR UniqueProcessId;
+ PVOID Reserved3;
+} PROCESS_BASIC_INFORMATION;
+typedef DWORD (*PNtQueryInformationProcess)(HANDLE, DWORD, PVOID, ULONG, PULONG);
+
+static HINSTANCE ntdll;
+static PNtQueryInformationProcess pNtQueryInformationProcess;
+static HANDLE heap;
+
+static HANDLE tracedProc;
+static DWORD tracedProcId;
+static TraceMode traceMode;
+static SectionInfo *sections;
+static IMAGE_DOS_HEADER mz_header;
+static IMAGE_NT_HEADERS pe_header;
+static BYTE hits_thumbnail[1025];
+static BOOL hasTraceData;
+static BOOL has_rdata;
+static DWORD last_activity;
+static int draw_num;
+#define ACTIVITY_FLASH_MS 100
+
+static BOOL CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
+static void ShowLastErrorDialog(HWND hwnd, char *format);
+static void ShowErrorDialog(HWND hwnd, char *format, DWORD errorCode);
+static BOOL toggle_attached_state(HWND hwnd, BOOL is_attached);
+static BOOL attach(HWND hwnd);
+static void detach();
+static void save_dump(HWND hwnd, char *filename);
+static BOOL patch_code(HWND hwnd, DWORD va_start, DWORD va_size);
+static DWORD next_function_start(BYTE *code, DWORD p, DWORD va_size);
+static void unpatch_loops(HWND hwnd);
+static void free_sections(HWND hwnd);
+static DWORD find_process(char *name);
+
+int WINAPI WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR cmdLine,
+ int windowState)
+
+{
+ HWND hwnd;
+ MSG msg;
+ HICON icon;
+ int status;
+
+ heap = GetProcessHeap();
+ InitCommonControls();
+/*{
+BYTE data[] = { 0x66, 0x39, 0x0f, 0x0f };
+ShowErrorDialog(NULL, "len = %1!d!", get_x86_instr_size(data, 0, sizeof(data)));
+ExitProcess(0);
+}*/
+
+ hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(ID_MAINDLG), 0, DialogProc);
+ if (!hwnd) {
+ ShowLastErrorDialog(0, "Error 0x%1!04x! occurred when trying to create dialog box.");
+ return 1;
+ }
+
+ icon = LoadIcon(hInstance, "A");
+ SendMessage(hwnd, WM_SETICON, ICON_BIG, (WPARAM)icon);
+ ShowWindow(hwnd, windowState);
+ while ((status = GetMessage(&msg, NULL, 0, 0)) != 0) {
+ if (status == -1) {
+ detach();
+ return -1;
+ }
+
+ if (!IsDialogMessage(hwnd, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ detach();
+ return msg.wParam;
+}
+
+static BOOL CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ EnableWindow(GetDlgItem(hwnd, ID_DETACH), FALSE);
+ EnableWindow(GetDlgItem(hwnd, ID_SAVE), FALSE);
+ /*CheckDlgButton(hwnd, ID_TRCCALL, BST_CHECKED);*/ /* Not implemented yet */
+ SetDlgItemText(hwnd, ID_PROCENTRY, "notepad.exe");
+ return TRUE;
+ case WM_COMMAND:
+ switch (wParam) {
+ case ID_ATTACH: {
+ /* Parse process id/name entry */
+ DWORD pid;
+ char buff[1024];
+ BOOL is_integer, ok;
+
+ buff[0] = '\0';
+ GetDlgItemText(hwnd, ID_PROCENTRY, buff, sizeof(buff));
+ if (!buff[0]) {
+ MessageBox(hwnd, "Please enter a process name or ID.", NULL, MB_ICONERROR);
+ return TRUE;
+ }
+
+ pid = GetDlgItemInt(hwnd, ID_PROCENTRY, &is_integer, FALSE);
+ if (!is_integer) {
+ /* Assume that it's a process name */
+ pid = find_process(buff);
+ if (!pid) {
+ MessageBox(hwnd, "Process not found (searched by name).", NULL, MB_ICONERROR);
+ return TRUE;
+ }
+ if (pid == (DWORD)-1) {
+ MessageBox(hwnd, "Multiple processes exist with this name. Please specify a PID.", NULL, MB_ICONEXCLAMATION);
+ return TRUE;
+ }
+ }
+
+ /*if (IsDlgButtonChecked(hwnd, ID_TRCCALL) == BST_CHECKED) {
+ traceMode = TRC_CALL;
+ } else if (IsDlgButtonChecked(hwnd, ID_TRCINT3) == BST_CHECKED) {
+ traceMode = TRC_INT3;
+ } else if (IsDlgButtonChecked(hwnd, ID_TRCLOOP) == BST_CHECKED) {
+ traceMode = TRC_LOOP;
+ }*/
+ traceMode = TRC_LOOP;
+
+ /* Open process */
+ detach();
+ tracedProcId = pid;
+ tracedProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid);
+ if (!tracedProc) {
+ if (is_integer && GetLastError() == ERROR_INVALID_PARAMETER) {
+ MessageBox(hwnd, "Process not found (searched by ID).", NULL, MB_ICONERROR);
+ } else {
+ ShowLastErrorDialog(hwnd, "Error 0x%1!04x! occurred when trying to open process.");
+ }
+ return TRUE;
+ }
+ free_sections(hwnd); /* clean up from previous runs */
+
+ ok = attach(hwnd);
+ if (ok) {
+ ZeroMemory(hits_thumbnail, sizeof(hits_thumbnail));
+ }
+ hasTraceData = ok;
+ toggle_attached_state(hwnd, ok);
+ EnableWindow(GetDlgItem(hwnd, ID_SAVE), ok);
+ return TRUE; }
+ case ID_DETACH:
+ detach();
+ toggle_attached_state(hwnd, FALSE);
+ return TRUE;
+ case ID_MENUBTN: {
+ RECT rect;
+ HMENU menu;
+ TPMPARAMS tpm;
+ int state;
+
+ /* Determine screen location of the button */
+ GetWindowRect((HWND)lParam, &rect);
+
+ /* Load menu and disable/enable items */
+ menu = LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_HITSMENU));
+ menu = GetSubMenu(menu, 0);
+ /*state = (tracedProc ? 0 : MF_GRAYED);
+ EnableMenuItem(menu, ID_ADDHITSCODE, state);
+ EnableMenuItem(menu, ID_ADDHITSRANGE, state);
+ EnableMenuItem(menu, ID_CLEARHITS, state);*/
+ EnableMenuItem(menu, ID_CLEARHITS, hasTraceData ? 0 : MF_GRAYED);
+
+ /* Show popup menu */
+ tpm.cbSize = sizeof(tpm);
+ tpm.rcExclude = rect;
+ int cmd = TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL | TPM_RETURNCMD,
+ rect.left, rect.bottom, hwnd, &tpm);
+ DestroyMenu(menu);
+ return TRUE;
+ }
+ case ID_SAVE: {
+ OPENFILENAME ofn = { 0 };
+ char path[MAX_PATH];
+ path[0] = '\0';
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hwnd;
+ ofn.hInstance = GetModuleHandle(NULL);
+ ofn.lpstrFilter = "LoopyTrace masked PE dump files (*.loopy.exe)\0*.loopy.exe\0All files (*.*)\0*.*\0\0";
+ ofn.lpstrFile = path;
+ ofn.nMaxFile = MAX_PATH-1;
+ ofn.lpstrTitle = "Save masked PE dump";
+ ofn.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
+ ofn.lpstrDefExt = "loopy.exe";
+ if (GetSaveFileName(&ofn)) {
+ save_dump(hwnd, ofn.lpstrFile);
+ }
+ return TRUE; }
+ case IDCANCEL:
+ case ID_EXIT:
+ PostQuitMessage(0);
+ return TRUE;
+ }
+ return TRUE;
+ case WM_CTLCOLORSTATIC:
+ if ((HWND)lParam == GetDlgItem(hwnd, ID_COPYRIGHT)) {
+ SetBkMode((HDC)wParam, TRANSPARENT);
+ SetTextColor((HDC)wParam, GetSysColor(COLOR_GRAYTEXT));
+ return (BOOL)CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+ }
+ return FALSE;
+ case WM_DRAWITEM: {
+ DRAWITEMSTRUCT *dis = (PDRAWITEMSTRUCT)lParam;
+ switch (dis->CtlID) {
+ case ID_HITS: {
+ int i;
+ int saved = SaveDC(dis->hDC);
+ DWORD now = GetTickCount();
+ COLORREF bgColor;
+ COLORREF hitColor;
+ if (!tracedProc) {
+ bgColor = 0xCCCCCC;
+ hitColor = 0x996666;
+ } else if (last_activity < now-ACTIVITY_FLASH_MS) {
+ bgColor = 0xDDBBBB;
+ hitColor = 0xCC3333;
+ } else if ((++draw_num & 1) == 0) {
+ bgColor = 0xBBBBDD;
+ hitColor = 0x3333CC;
+ } else {
+ bgColor = 0xCCCCEE;
+ hitColor = 0x3A3ADD;
+ }
+ HBRUSH bgBrush = CreateSolidBrush(bgColor);
+ HBRUSH hitBrush = CreateSolidBrush(hitColor);
+
+ FillRect(dis->hDC, &dis->rcItem, bgBrush);
+ if (hasTraceData) {
+ BOOL was_on = FALSE;
+ RECT on_rect;
+ on_rect.left = 0;
+ on_rect.top = 0;
+ on_rect.bottom = dis->rcItem.bottom;
+ for (i = 0; i < 1024; i++) {
+ BOOL on = hits_thumbnail[i] & HIT_REACHED;
+ if (on && !was_on) {
+ on_rect.left = i*dis->rcItem.right / 1024;
+ was_on = TRUE;
+ } else if (!on && was_on) {
+ on_rect.right = i*dis->rcItem.right / 1024;
+ FillRect(dis->hDC, &on_rect, hitBrush);
+ was_on = FALSE;
+ }
+ }
+
+ if (was_on) {
+ on_rect.right = dis->rcItem.right;
+ FillRect(dis->hDC, &on_rect, hitBrush);
+ }
+ }
+
+ RestoreDC(dis->hDC, saved);
+ DeleteObject(bgBrush);
+ DeleteObject(hitBrush);
+ return TRUE; }
+ }
+ return FALSE; }
+ case WM_TIMER:
+ switch (wParam) {
+ case ID_PATCHTIMER:
+ unpatch_loops(hwnd);
+ break;
+ case ID_UITIMER:
+ InvalidateRect(GetDlgItem(hwnd, ID_HITS), NULL, FALSE);
+ break;
+ }
+ return TRUE;
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return TRUE;
+ case WM_CLOSE:
+ DestroyWindow(hwnd);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static BOOL toggle_attached_state(HWND hwnd, BOOL is_attached)
+{
+ if (is_attached) {
+ EnableWindow(GetDlgItem(hwnd, ID_ATTACH), FALSE);
+ EnableWindow(GetDlgItem(hwnd, ID_DETACH), TRUE);
+ SetTimer(hwnd, ID_PATCHTIMER, 1, NULL); /* FIXME maybe it shouldn't be a timer? */
+ SetTimer(hwnd, ID_UITIMER, 100, NULL);
+ } else {
+ EnableWindow(GetDlgItem(hwnd, ID_ATTACH), TRUE);
+ EnableWindow(GetDlgItem(hwnd, ID_DETACH), FALSE);
+ KillTimer(hwnd, ID_PATCHTIMER);
+ KillTimer(hwnd, ID_UITIMER);
+ InvalidateRect(GetDlgItem(hwnd, ID_HITS), NULL, FALSE);
+ }
+}
+
+static DWORD find_process(char *name)
+{
+ PROCESSENTRY32 entry;
+ DWORD foundPid = 0;
+ entry.dwSize = sizeof(entry);
+
+ HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (Process32First(snapshot, &entry)) {
+ do {
+ if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, name, -1, entry.szExeFile, -1) == CSTR_EQUAL) {
+ if (foundPid) {
+ foundPid = (DWORD)-1; /* Multiple processes with this name */
+ break;
+ }
+ foundPid = entry.th32ProcessID;
+ }
+ } while (Process32Next(snapshot, &entry));
+ }
+ CloseHandle(snapshot);
+ return foundPid;
+}
+
+static BOOL enable_debug_privs(HWND hwnd)
+{
+ HANDLE token = 0;
+ TOKEN_PRIVILEGES privs = { 0 };
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) {
+ if (hwnd) {
+ MessageBox(0, "Tried to adjust own debug privileges, but OpenProcessToken failed.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privs.Privileges[0].Luid)) {
+ if (hwnd) {
+ MessageBox(0, "Tried to adjust own debug privileges, but LookupPrivilegeValue failed.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ privs.PrivilegeCount = 1;
+ privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if (!AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, 0)) {
+ if (hwnd) {
+ MessageBox(0, "Tried to adjust own debug privileges, but AdjustTokenPrivilege failed.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* hwnd is a handle of the main window */
+/* TODO for programs that destroy their headers (if that's possible?) we
+ should also implement reading of the EXE file, and/or simply trying to find
+ all executable pages by brute force (could use VirtualQueryEx) */
+static BOOL attach(HWND hwnd)
+{
+ DWORD res;
+ PROCESS_BASIC_INFORMATION pbi;
+ DWORD imagebase = 0;
+ DWORD pe_start;
+ DWORD sections_start;
+ IMAGE_SECTION_HEADER *sectiontable;
+ int num_sections, i;
+
+ /* Look up NtQueryInformationProcess function */
+ if (!ntdll) {
+ ntdll = LoadLibrary("ntdll");
+ if (!ntdll && hwnd) {
+ MessageBox(hwnd, "Failed to load NTDLL library.", NULL, MB_ICONERROR);
+ }
+ }
+
+ if (ntdll && !pNtQueryInformationProcess) {
+ pNtQueryInformationProcess = (PNtQueryInformationProcess)GetProcAddress(ntdll, "NtQueryInformationProcess");
+ if (!pNtQueryInformationProcess && hwnd) {
+ MessageBox(hwnd, "Missing function NtQueryInformationProcess in NTDLL library.", NULL, MB_ICONERROR);
+ }
+ }
+
+ /* Get image base */
+ if (pNtQueryInformationProcess) {
+ if (enable_debug_privs(hwnd)) {
+ res = pNtQueryInformationProcess(tracedProc, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
+ if (res != 0) {
+ if (hwnd) {
+ ShowErrorDialog(hwnd, "NtQueryInformationProcess failed with error 0x%1!04x!", res);
+ }
+ } else if (!ReadProcessMemory(tracedProc, (char*)pbi.PebBaseAddress + 8, &imagebase, sizeof(imagebase), NULL) && hwnd) {
+ MessageBox(hwnd, "Failed to read image base.", NULL, MB_ICONERROR);
+ }
+ }
+ }
+
+ if (!imagebase) {
+ if (hwnd) {
+ /* TODO ask for image base instead. Usually it's either 0x00400000 or 0x01000000 */
+ /* TODO or could try a brute force scan in this case */
+ imagebase = 0x00400000;
+ } else {
+ imagebase = 0x00400000; /* might work */
+ }
+ if (!imagebase) {
+ return FALSE;
+ }
+ }
+
+ /* Get MZ header */
+ if (!ReadProcessMemory(tracedProc, (PCVOID)imagebase, &mz_header, sizeof(mz_header), NULL)) {
+ if (hwnd) {
+ MessageBox(hwnd, "Failed to read EXE/MZ header at image base.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ if (mz_header.e_magic != 0x5A4D && mz_header.e_magic != 0x4D5A) { /* MZ or ZM */
+ if (hwnd) {
+ MessageBox(hwnd, "Data at image base is not an MZ header.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ /* Get PE header */
+ pe_start = imagebase + mz_header.e_lfanew;
+ if (!ReadProcessMemory(tracedProc, (PCVOID)pe_start, &pe_header, sizeof(pe_header), NULL)) {
+ if (hwnd) {
+ MessageBox(hwnd, "Failed to read memory of PE header.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ if (pe_header.Signature != 0x4550) {
+ if (hwnd) {
+ MessageBox(hwnd, "Data referenced by MZ e_lfanew offset is not an PE header.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ /* Get section table */
+ sections_start = pe_start +
+ sizeof(pe_header.Signature) +
+ sizeof(pe_header.FileHeader) +
+ pe_header.FileHeader.SizeOfOptionalHeader;
+ num_sections = pe_header.FileHeader.NumberOfSections;
+ sectiontable = HeapAlloc(heap, 0, num_sections*sizeof(IMAGE_SECTION_HEADER));
+ if (!sectiontable) {
+ if (hwnd) {
+ MessageBox(hwnd, "Failed to allocate memory for section table.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ if (!ReadProcessMemory(tracedProc, (PCVOID)sections_start, sectiontable, num_sections*sizeof(IMAGE_SECTION_HEADER), NULL)) {
+ if (hwnd) {
+ MessageBox(hwnd, "Failed to read memory of section header.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ /* Determine if we have an rdata section */
+ has_rdata = FALSE;
+ for (i = 0; i < num_sections; i++) {
+ if ((sectiontable[i].Characteristics & (IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_MEM_EXECUTE)) != IMAGE_SCN_CNT_INITIALIZED_DATA)
+ continue;
+
+ if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE|NORM_IGNORESYMBOLS|SORT_STRINGSORT, sectiontable[i].Name, -1, ".rdata", -1) != CSTR_EQUAL &&
+ CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE|NORM_IGNORESYMBOLS|SORT_STRINGSORT, sectiontable[i].Name, -1, ".rodata", -1) != CSTR_EQUAL)
+ continue;
+
+ has_rdata = TRUE;
+ MessageBox(0, "HAS rdata", "", 64);
+ }
+
+ /* Patch code sections */
+ for (i = 0; i < num_sections; i++) {
+ DWORD va_start, va_size;
+
+ if ((sectiontable[i].Characteristics & (IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) == 0) {
+ continue;
+ }
+
+ va_start = imagebase + sectiontable[i].VirtualAddress;
+ va_size = sectiontable[i].Misc.VirtualSize;
+
+ //ShowErrorDialog(hwnd, "Found code section starting at %1!08x!", va_start);
+ patch_code(hwnd, va_start, va_size);
+
+break; /* Don't patch bidvm sections */
+ }
+
+ HeapFree(heap, 0, sectiontable);
+ last_activity = 0;
+ draw_num = 0;
+ return TRUE;
+}
+
+static BOOL patch_code(HWND hwnd, DWORD va_start, DWORD va_size)
+{
+ BYTE *orig;
+ SectionInfo *section;
+
+ /* Add to linked list */
+ section = HeapAlloc(heap, 0, sizeof(SectionInfo));
+ section->va_start = va_start;
+ section->va_size = va_size;
+ section->orig = NULL;
+ section->hits = HeapAlloc(heap, HEAP_ZERO_MEMORY, va_size);
+ section->next = sections;
+ sections = section;
+
+ /* Read existing code */
+ orig = HeapAlloc(heap, 0, va_size);
+ if (!orig) {
+ if (hwnd) {
+ MessageBox(hwnd, "Failed to allocate memory for code section.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+ section->orig = orig;
+
+ if (!ReadProcessMemory(tracedProc, (PCVOID)va_start, orig, va_size, NULL)) {
+ if (hwnd) {
+ MessageBox(hwnd, "Failed to read memory of code section.", NULL, MB_ICONERROR);
+ }
+ return FALSE;
+ }
+
+ /* Run a pass over the code and scan for data references, and mark the
+ referenced data as non-code (if it's in the code section). */
+ // TODO
+ // TODO what to do with indexed access, e.g. call [PTRTABLE+i] ?
+
+ /* Patch code */
+ switch (traceMode) {
+ case TRC_CALL:
+ /* TODO */
+ break;
+ case TRC_INT3:
+ /* TODO */
+ break;
+ case TRC_LOOP: {
+ /* If the EXE doesn't have any .rdata section, assume it was smaller
+ than a page (4K) and has been merged with the code section(s) */
+ DWORD p = (has_rdata ? 0 : 0x1000);
+ while (p < va_size) {
+ /* JMP -2 with prefixes to allow instructions up to 15 bytes (the maximum) to be replaced */
+ //static const BYTE infinite_loop[15] = { 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x2E, 0xEB, 0xFE };
+ static const BYTE infinite_loop[2] = { 0xEB, 0xFE };
+
+
+ /* Skip one-byte instructions */
+ /*
+ BYTE instrsize;
+ int skipped = 0;
+ for (;;) {
+ if (p >= va_size) goto patch_loop_end;
+ if (skipped++ > 5) goto patch_loop_end;
+ instrsize = get_x86_instr_size(orig, p, va_size);
+ if (instrsize >= 2) break;
+ p += instrsize;
+ }*/
+
+ /* Patch function */
+ if ((section->hits[p] & HIT_IGNORED) == 0) {
+ //if (!WriteProcessMemory(tracedProc, (LPVOID)(va_start + p), (LPCVOID)&infinite_loop[15-instrsize], instrsize, NULL)) {
+ if (!WriteProcessMemory(tracedProc, (LPVOID)(va_start + p), (LPCVOID)infinite_loop, 2, NULL)) {
+ MessageBox(hwnd, "Failed to patch memory in code section.", NULL, MB_ICONERROR);
+ break;
+ }
+ section->hits[p] |= HIT_PATCHED;
+ }
+ p += 2/*instrsize*/;
+
+ p = next_function_start(orig, p, va_size);
+ }
+ patch_loop_end:
+ break; }
+ case TRC_NX:
+ /* TODO */
+ break;
+ }
+ return TRUE;
+}
+
+static DWORD next_function_start(BYTE *code, DWORD p, DWORD va_size)
+{
+ int gapsize;
+ do {
+ /* Search for return opcode */
+ for (;;) {
+ BYTE c, opsize;
+
+ if (p >= va_size) goto end;
+ c = code[p];
+
+ if (c == 0xC3) break; /* ret (we ignore retf since it's not used in Win32 programs) */
+ if (c == 0xC2) { p += 2; break; } /* ret WORD */
+
+ opsize = get_x86_instr_size(code, p, va_size);
+ if (opsize == 255 && p < va_size && (code[p] != 0 || p < va_size-15)) {
+ /*ShowErrorDialog(0, "Invalid opcode at 0x%1!08x! (relative to section start)", p);*/
+ opsize = 1;
+ }
+ p += opsize;
+ }
+ p++;
+
+ /* Skip NOP and INT3 gap between functions */
+ gapsize = 0;
+ for (;;) {
+ if (p >= va_size) goto end;
+ if (code[p] != 0x90 && code[p] != 0xCC) break;
+ gapsize++;
+ p++;
+ }
+
+ /* Check that's it's actually valid code */
+ {
+ BYTE opsize = get_x86_instr_size(code, p, va_size);
+ if (opsize == 255 && p < va_size-20) continue;
+ if (code[p+2] < 0x10 && code[p+3] == 0x01) {
+ /* Check for jump table with a single entry */
+ if ((code[p+4] == 0x90 || code[p+4] == 0xCC) &&
+ (code[p+5] == 0x90 || code[p+5] == 0xCC)) {
+ continue;
+ }
+ }
+ if (code[p+2] == code[p+6] && code[p+6] == code[p+10] &&
+ code[p+3] == code[p+7] && code[p+7] == code[p+11] &&
+ opsize != 4) {
+ /* Probably a jump table */
+ continue;
+ }
+ if (code[p+2] == code[p+10] && code[p+2] == code[p+18] &&
+ code[p+3] == code[p+11] && code[p+3] == code[p+19] &&
+ opsize != 4 && opsize != 8) {
+ /* Probably a jump table with data imbetween */
+ continue;
+ }
+ }
+
+ // TODO should ignore if the instr is single-byte and we aren't sure it's a function
+ /*if (gapsize == 0 && get_x86_instr_size(code, p, va_size) == 1) {
+ continue;
+ }*/
+
+ /* If we are at an even 8-byte boundary OR we saw at least one NOP/INT3
+ then we assume it's a start of a function */
+ } while ((p & 0x7) != 0 && gapsize == 0);
+ end:
+ return p;
+}
+
+static void unpatch_loops(HWND hwnd)
+{
+ THREADENTRY32 entry;
+ BOOL foundProcess = FALSE;
+ BOOL activity = FALSE;
+ entry.dwSize = sizeof(entry);
+
+ /* Enumerate all threads of the traced process */
+ HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (Thread32First(snapshot, &entry)) {
+ do {
+ CONTEXT ctx;
+ HANDLE hthread;
+ BOOL ok;
+ DWORD eip, func_end, p;
+ SectionInfo *section;
+ BYTE data[2];
+ BYTE instrsize;
+
+ /* Thread of a traced process? */
+ if (entry.th32OwnerProcessID != tracedProcId) {
+ continue;
+ }
+ foundProcess = TRUE;
+
+ /* Get EIP */
+ ZeroMemory(&ctx, sizeof(ctx));
+ ctx.ContextFlags = CONTEXT_CONTROL;
+ hthread = OpenThread(THREAD_GET_CONTEXT, FALSE, entry.th32ThreadID);
+ ok = GetThreadContext(hthread, &ctx);
+ CloseHandle(hthread);
+ if (!ok) {
+ continue;
+ }
+ eip = ctx.Eip;
+
+ /* Check if it was patched and is not reached/unpatched */
+ for (section = sections; section; section = section->next) {
+ if (eip >= section->va_start && eip < section->va_start + section->va_size) {
+ break;
+ }
+ }
+ if (!section || section->hits[eip-section->va_start] != HIT_PATCHED) {
+ continue;
+ }
+
+ /* Read memory at EIP */
+ p = eip-section->va_start;
+ if (ReadProcessMemory(tracedProc, (PCVOID)eip, data, 2, NULL)) {
+ if (data[0] != 0xEB || data[1] != 0xFE) {
+ //if (data[0] != 0xEB && data[0] != 0x26) {
+ /* Patch code has been overwritten */
+ continue;
+ }
+ }
+
+ /* Restore original memory */
+ /*instrsize = get_x86_instr_size(section->orig, p, section->va_size);
+ if (instrsize == 255) instrsize = 15;*/
+ WriteProcessMemory(tracedProc, (LPVOID)eip, §ions->orig[p], 2, NULL);
+
+ func_end = next_function_start(section->orig, eip-section->va_start, section->va_size);
+ for (; p < func_end; p++) {
+ section->hits[p] |= HIT_REACHED;
+ hits_thumbnail[p*1024/section->va_size] |= HIT_REACHED;
+ }
+
+ activity = TRUE;
+ } while (Thread32Next(snapshot, &entry));
+ }
+ CloseHandle(snapshot);
+
+ if (activity) {
+ last_activity = GetTickCount();
+ } else {
+ draw_num = 0;
+ }
+
+ if (!foundProcess) {
+ CloseHandle(tracedProc);
+ tracedProc = 0;
+ tracedProcId = 0;
+ toggle_attached_state(hwnd, FALSE);
+ }
+}
+
+static void detach(HWND hwnd)
+{
+ if (tracedProc) {
+ /* Restore process memory */
+ SectionInfo *section, *tmp;
+ BOOL failed = FALSE;
+ for (section = sections; section; section = section->next) {
+ if (!WriteProcessMemory(tracedProc, (LPVOID)section->va_start, section->orig, section->va_size, NULL)) {
+ failed = TRUE;
+ }
+ }
+
+ if (failed && hwnd) {
+ MessageBox(hwnd, "Failed to restore memory of code section.", NULL, MB_ICONERROR);
+ }
+
+ CloseHandle(tracedProc);
+ }
+ tracedProc = 0;
+ tracedProcId = 0;
+}
+
+static void free_sections(HWND hwnd)
+{
+ SectionInfo *section, *next;
+ for (section = sections; section; section = next) {
+ next = section->next;
+ HeapFree(heap, 0, section);
+ }
+ sections = NULL;
+}
+
+#define ROUNDPG(n) (((n)+0xFFF) & ~0xFFF)
+static void save_dump(HWND hwnd, char *filename)
+{
+ DWORD num_code, size_code, num_other, size_init, size_uninit;
+ DWORD byteswritten;
+ IMAGE_DOS_HEADER doshdr;
+ IMAGE_NT_HEADERS nthdr;
+ IMAGE_SECTION_HEADER sectiontable[1];
+ SectionInfo *section;
+ HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ if (hwnd) {
+ ShowLastErrorDialog(hwnd, "Failed to save file! Error: 0x%1!04x!");
+ }
+ return;
+ }
+
+ /* Determine number of sections */
+ num_code = 0;
+ size_code = 0;
+ num_other = 0;
+ size_init = 0;
+ size_uninit = 0;
+ for (section = sections; section; section = section->next) {
+ num_code++;
+ size_code += section->va_size;
+ }
+ /* TODO copy non-code sections from the process as-is */
+ /* TODO fill ignored code sections with 0x90 */
+
+ /* Write header */
+ ZeroMemory(&doshdr, sizeof(doshdr));
+ doshdr.e_magic = IMAGE_DOS_SIGNATURE;
+ doshdr.e_cblp = 0x90;
+ doshdr.e_cp = 3;
+ doshdr.e_cparhdr = 4;
+ doshdr.e_maxalloc = 0xFFFF;
+ doshdr.e_sp = 0xB8;
+ doshdr.e_lfarlc = 0;
+ doshdr.e_lfanew = /*0x20*/ sizeof(doshdr);
+ WriteFile(file, &doshdr, sizeof(doshdr), &byteswritten, NULL);
+ ZeroMemory(&nthdr, sizeof(nthdr));
+ nthdr.Signature = IMAGE_NT_SIGNATURE;
+ nthdr.FileHeader.Machine = 0x14C; /* i386 */
+ nthdr.FileHeader.NumberOfSections = num_code + num_other;
+ nthdr.FileHeader.TimeDateStamp = 0;
+ nthdr.FileHeader.SizeOfOptionalHeader = 0xE0;
+ nthdr.FileHeader.Characteristics = 0x103; /* executable, stripped relocs, 32-bit */
+ nthdr.OptionalHeader.Magic = 0x10B; /* PE32 */
+ nthdr.OptionalHeader.MajorLinkerVersion = 8;
+ nthdr.OptionalHeader.SizeOfCode = ROUNDPG(size_code);
+ nthdr.OptionalHeader.SizeOfInitializedData = ROUNDPG(size_init);
+ nthdr.OptionalHeader.SizeOfUninitializedData = ROUNDPG(size_uninit);
+ nthdr.OptionalHeader.AddressOfEntryPoint = 0x1000; /* FIXME */
+ nthdr.OptionalHeader.BaseOfCode = sections->va_start & 0xFFFF;
+ nthdr.OptionalHeader.BaseOfData = 0x50000; /* TODO */
+ nthdr.OptionalHeader.ImageBase = sections->va_start & ~0xFFFF;
+ nthdr.OptionalHeader.SectionAlignment = 0x1000;
+ nthdr.OptionalHeader.FileAlignment = 0x1000;
+ nthdr.OptionalHeader.MajorOperatingSystemVersion = 4;
+ nthdr.OptionalHeader.MajorSubsystemVersion = 4;
+ nthdr.OptionalHeader.SizeOfImage = 0x1000+ROUNDPG(size_code)+ROUNDPG(size_init);
+ nthdr.OptionalHeader.SizeOfHeaders = 0x1000;
+ nthdr.OptionalHeader.CheckSum = 0; /* TODO */
+ nthdr.OptionalHeader.Subsystem = 2; /* Windows GUI */
+ nthdr.OptionalHeader.SizeOfStackReserve = 0x100000;
+ nthdr.OptionalHeader.SizeOfStackCommit = 0x1000;
+ nthdr.OptionalHeader.SizeOfHeapReserve = 0x100000;
+ nthdr.OptionalHeader.SizeOfHeapCommit = 0x1000;
+ nthdr.OptionalHeader.NumberOfRvaAndSizes = 0x10;
+ WriteFile(file, &nthdr, sizeof(nthdr), &byteswritten, NULL);
+
+ /* Write section table */
+ ZeroMemory(§iontable, sizeof(sectiontable));
+ lstrcpy(sectiontable[0].Name, ".text");
+ sectiontable[0].Misc.VirtualSize = sections->va_size;
+ sectiontable[0].VirtualAddress = sections->va_start & 0xFFFF;
+ sectiontable[0].SizeOfRawData = ROUNDPG(sections->va_size);
+ sectiontable[0].PointerToRawData = 0x1000;
+ sectiontable[0].Characteristics = IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_EXECUTE;
+ WriteFile(file, sectiontable, sizeof(sectiontable), &byteswritten, NULL);
+
+ /* Write section contents */
+ /* TODO write all code sections */
+ SetFilePointer(file, 0x1000, NULL, FILE_BEGIN);
+ {
+ int i, len = sections->va_size;
+ BYTE *data = HeapAlloc(heap, 0, len);
+ FillMemory(data, len, 0x90); /* Fill with NOP */
+ for (i = 0; i < len; i++) {
+ if ((sections->hits[i] & HIT_REACHED) != 0) {
+ /* Only reached code is included */
+ data[i] = sections->orig[i];
+ }
+ }
+ WriteFile(file, data, len, &byteswritten, NULL);
+ HeapFree(heap, 0, data);
+ }
+ /* TODO for others: simply output as-is */
+
+ /* Padding */
+ SetFilePointer(file, 0x1000+ROUNDPG(size_code)+ROUNDPG(size_init), NULL, FILE_BEGIN);
+ SetEndOfFile(file);
+
+ CloseHandle(file);
+}
+
+static void ShowLastErrorDialog(HWND hwnd, char *format)
+{
+ ShowErrorDialog(hwnd, format, GetLastError());
+}
+
+static void ShowErrorDialog(HWND hwnd, char *format, DWORD errorCode)
+{
+ char buff[1024];
+ DWORD_PTR fmtargs[1] = { (DWORD_PTR)errorCode };
+ buff[0] = 'A';
+ FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, format, 0, 0, buff, sizeof(buff), (va_list*)fmtargs);
+ MessageBox(hwnd, buff, NULL, MB_ICONERROR | MB_OK);
+}
+
+// BUGS:
+// - nothing is traced in winmine.exe - why? doesn't seem to have any NOP gaps
+// - Call FlushInstructionCache(hprocess, startaddr, size)
+//
+
+// POSSIBLE NEW FEATURES:
+// - log parameters in calls. Try to detect parameter types (e.g. address -> log data)
+//
+
+// POSSIBLE NEW TRACING METHODS:
+// - scan the stack for return addresses instead? (from this we can also check the call instr before and determine the called address)
+// completely passive. need to filter out non-return-code data on the stack (can check that there's a call instr).
+// could also scan for current EIP.
+// - somehow probe the I-cache?
+//
diff --git a/HitTrace/main.rc b/HitTrace/main.rc new file mode 100644 index 0000000..62fc13d --- /dev/null +++ b/HitTrace/main.rc @@ -0,0 +1,69 @@ +/*
+
+ Copyright (c) 2014-2015 Samuel Lidén Borell <samuel@kodafritt.se>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+*/
+
+#include "resource.h"
+
+ID_MAINDLG DIALOGEX 0, 0, 225, 99
+CAPTION "LoopyTrace - Hit trace 0.1.0"
+STYLE WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | DS_CENTER | DS_SHELLFONT
+FONT 8, "MS Shell Dlg"
+{
+ LTEXT "&Process:", ID_PROCLABEL, 10, 11, 40, 10
+ EDITTEXT ID_PROCENTRY, 45, 10, 60, 12
+ LTEXT "(PID or name)", ID_PROCHINT, 110, 11, 50, 10
+
+ PUSHBUTTON "&Trace" , ID_ATTACH, 165, 9, 50, 14, BS_DEFPUSHBUTTON
+ PUSHBUTTON "&Stop", ID_DETACH, 165, 27, 50, 14
+
+ /*LTEXT "Tracing:", ID_TRCLABEL, 10, 32, 40, 10
+ AUTORADIOBUTTON "CALL", ID_TRCCALL, 45, 32, 30, 10, WS_GROUP | WS_DISABLED // not implemented
+ AUTORADIOBUTTON "INT3", ID_TRCINT3, 75, 32, 30, 10, WS_DISABLED
+ AUTORADIOBUTTON "Loop", ID_TRCLOOP, 105, 32, 30, 10
+ AUTORADIOBUTTON "NX", ID_TRCNX, 135, 32, 20, 10, WS_GROUP | WS_DISABLED*/
+
+ // TODO implement extra functions in menu
+ //PUSHBUTTON ">", ID_MENUBTN, 10, 52, 12, 11, BS_BOTTOM
+ //LTEXT "", ID_HITS, 22, 53, 133, 10, SS_OWNERDRAW
+ LTEXT "", ID_HITS, 10, 53, 145, 10, SS_OWNERDRAW
+ PUSHBUTTON "&Save", ID_SAVE, 165, 51, 50, 14
+
+ LTEXT "https://github.com/samuellb/loopytrace/\nThis is free software (MIT license)", ID_COPYRIGHT, 10, 70, 145, 20, SS_NOPREFIX
+ //LTEXT "", ID_COPYRIGHT, 10, 70, 145, 20, SS_NOPREFIX
+ PUSHBUTTON "E&xit", ID_EXIT, 165, 75, 50, 14
+}
+
+// TODO these are not implemented!
+ID_HITSMENU MENU
+{
+ POPUP ""
+ {
+ MENUITEM "Ignore from dump...", ID_ADDIGNCODE
+ MENUITEM "Ignore from range...", ID_ADDIGNRANGE
+ MENUITEM "Clear ignores", ID_CLEARIGN
+ MENUITEM SEPARATOR
+ MENUITEM "Mark hits from dump...", ID_ADDHITSCODE
+ MENUITEM "Mark range as hit...", ID_ADDHITSRANGE
+ MENUITEM "&Clear hits", ID_CLEARHITS
+ }
+}
diff --git a/HitTrace/resource.h b/HitTrace/resource.h new file mode 100644 index 0000000..7912b43 --- /dev/null +++ b/HitTrace/resource.h @@ -0,0 +1,56 @@ +/*
+
+ Copyright (c) 2014-2015 Samuel Lidén Borell <samuel@kodafritt.se>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+*/
+
+/* Controls (except for buttons) */
+#define ID_MAINDLG 1000
+#define ID_PROCLABEL 1001
+#define ID_PROCENTRY 1002
+#define ID_PROCHINT 1003
+#define ID_TRCLABEL 1011
+#define ID_TRCCALL 1012
+#define ID_TRCINT3 1013
+#define ID_TRCLOOP 1014
+#define ID_TRCNX 1015
+#define ID_HITS 1021
+#define ID_COPYRIGHT 1031
+
+/* Misc. stuff */
+#define ID_PATCHTIMER 1801
+#define ID_UITIMER 1802
+#define ID_HITSMENU 1803
+
+/* Buttons */
+#define ID_ATTACH 1901
+#define ID_DETACH 1902
+#define ID_SAVE 1903
+#define ID_MENUBTN 1904
+#define ID_EXIT 1905
+
+/* Menu */
+#define ID_ADDIGNCODE 1951
+#define ID_ADDIGNRANGE 1952
+#define ID_CLEARIGN 1953
+#define ID_ADDHITSCODE 1954
+#define ID_ADDHITSRANGE 1955
+#define ID_CLEARHITS 1956
diff --git a/HitTrace/x86ops.c b/HitTrace/x86ops.c new file mode 100644 index 0000000..5425021 --- /dev/null +++ b/HitTrace/x86ops.c @@ -0,0 +1,754 @@ +/*
+
+ Copyright (c) 2014-2015 Samuel Lidén Borell <samuel@kodafritt.se>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+*/
+
+#include "x86ops.h"
+#include <stdio.h>
+
+typedef unsigned char BYTE;
+
+//#define ILLEGAL_INSTR_SIZE 1
+#define ILLEGAL_INSTR_SIZE 255
+
+/*#define OPND_BW 0x10*/
+#define OPND_WD 0x20 /* 16/32-bit */
+#define OPND_PP 0x30 /* 16/32-bit (although some web page says 32/48-bit) */
+#define ADDR_WD 0x40 /* 16/32-bit */
+#define OPNDADDRMASK 0x70
+#define MODRM 0x80
+#define ILLEGAL 0xF0
+#define PREFIX 0xF1
+#define TWOBYTE 0xF2
+#define MULTI 0xF3
+static const unsigned char opinfos[256] = {
+ /* 0x00 - 0x0F */
+ 1|MODRM,/* 0: ADD modrm8 */
+ 1|MODRM,/* 1: ADD modrm16/32 */
+ 1|MODRM,/* 2: ADD modrm8 reversed */
+ 1|MODRM,/* 3: ADD modrm16/32 reversed */
+ 1+1, /* 4: ADD AL, imm8 */
+ 1|OPND_WD,/* 5: ADD, EAX, imm16/32 */
+ 1, /* 6: PUSH ES */
+ 1, /* 7: POP ES */
+ 1|MODRM,/* 8: OR modrm8 */
+ 1|MODRM,/* 9: OR modrm16/32 */
+ 1|MODRM,/* A: OR modrm8 reversed */
+ 1|MODRM,/* B: OR modrm16/32 reversed */
+ 1+1, /* C: OR AL, imm8 */
+ 1|OPND_WD,/* D: OR, EAX, imm16/32 */
+ 1, /* E: PUSH CS */
+ TWOBYTE,/* F: two byte instruction */
+
+ /* 0x10 - 0x1F */
+ 1|MODRM,/* 0: ADC modrm8 */
+ 1|MODRM,/* 1: ADC modrm16/32 */
+ 1|MODRM,/* 2: ADC modrm8 reversed */
+ 1|MODRM,/* 3: ADC modrm16/32 reversed */
+ 1+1, /* 4: ADC AL, imm8 */
+ 1|OPND_WD,/* 5: ADC, EAX, imm16/32 */
+ 1, /* 6: PUSH SS */
+ 1, /* 7: POP SS */
+ 1|MODRM,/* 8: SBB modrm8 */
+ 1|MODRM,/* 9: SBB modrm16/32 */
+ 1|MODRM,/* A: SBB modrm8 reversed */
+ 1|MODRM,/* B: SBB modrm16/32 reversed */
+ 1+1, /* C: SBB AL, imm8 */
+ 1|OPND_WD,/* D: SBB, EAX, imm16/32 */
+ 1, /* E: PUSH DS */
+ 1, /* F: POP DS */
+
+ /* 0x20 - 0x2F */
+ 1|MODRM,/* 0: AND modrm8 */
+ 1|MODRM,/* 1: AND modrm16/32 */
+ 1|MODRM,/* 2: AND modrm8 reversed */
+ 1|MODRM,/* 3: AND modrm16/32 reversed */
+ 1+1, /* 4: AND AL, imm8 */
+ 1|OPND_WD,/* 5: AND, EAX, imm16/32 */
+ PREFIX, /* 6: prefix DS: */
+ 1, /* 7: DAA */
+ 1|MODRM,/* 8: SUB modrm8 */
+ 1|MODRM,/* 9: SUB modrm16/32 */
+ 1|MODRM,/* A: SUB modrm8 reversed */
+ 1|MODRM,/* B: SUB modrm16/32 reversed */
+ 1+1, /* C: SUB AL, imm8 */
+ 1|OPND_WD,/* D: SUB, EAX, imm16/32 */
+ PREFIX, /* E: prefix CS: */
+ 1, /* F: DAS */
+
+ /* 0x30 - 0x3F */
+ 1|MODRM,/* 0: XOR modrm8 */
+ 1|MODRM,/* 1: XOR modrm16/32 */
+ 1|MODRM,/* 2: XOR modrm8 reversed */
+ 1|MODRM,/* 3: XOR modrm16/32 reversed */
+ 1+1, /* 4: XOR AL, imm8 */
+ 1|OPND_WD,/* 5: XOR, EAX, imm16/32 */
+ PREFIX, /* 6: prefix SS: */
+ 1, /* 7: AAA */
+ 1|MODRM,/* 8: CMP modrm8 */
+ 1|MODRM,/* 9: CMP modrm16/32 */
+ 1|MODRM,/* A: CMP modrm8 reversed */
+ 1|MODRM,/* B: CMP modrm16/32 reversed */
+ 1+1, /* C: CMP AL, imm8 */
+ 1|OPND_WD,/* D: CMP, EAX, imm16/32 */
+ PREFIX, /* E: prefix DS: */
+ 1, /* F: AAS */
+
+ /* 0x40 - 0x4F */
+ 1, /* 0: INC EAX */
+ 1, /* 1: INC ECX */
+ 1, /* 2: INC EDX */
+ 1, /* 3: INC EBX */
+ 1, /* 4: INC ESP */
+ 1, /* 5: INC EBP */
+ 1, /* 6: INC ESI */
+ 1, /* 7: INC EDI */
+ 1, /* 8: DEC EAX */
+ 1, /* 9: DEC ECX */
+ 1, /* A: DEC EDX */
+ 1, /* B: DEC EBX */
+ 1, /* C: DEC ESP */
+ 1, /* D: DEC EBP */
+ 1, /* E: DEC ESI */
+ 1, /* F: DEC EDI */
+
+ /* 0x50 - 0x5F */
+ 1, /* 0: PUSH EAX */
+ 1, /* 1: PUSH ECX */
+ 1, /* 2: PUSH EDX */
+ 1, /* 3: PUSH EBX */
+ 1, /* 4: PUSH ESP */
+ 1, /* 5: PUSH EBP */
+ 1, /* 6: PUSH ESI */
+ 1, /* 7: PUSH EDI */
+ 1, /* 8: POP EAX */
+ 1, /* 9: POP ECX */
+ 1, /* A: POP EDX */
+ 1, /* B: POP EBX */
+ 1, /* C: POP ESP */
+ 1, /* D: POP EBP */
+ 1, /* E: POP ESI */
+ 1, /* F: POP EDI */
+
+ /* 0x60 - 0x6F */
+ 1, /* 0: PUSHA */
+ 1, /* 1: POPA */
+ 1|MODRM,/* 2: BOUND */
+ 1|MODRM,/* 3: ARPL */
+ PREFIX, /* 4: prefix */
+ PREFIX, /* 5: prefix */
+ PREFIX, /* 6: prefix */
+ PREFIX, /* 7: prefix */
+ 1|OPND_WD,/* 8: PUSH imm16/32 */
+ 1|MODRM|OPND_WD,/* 9: IMUL */
+ 1+1, /* A: PUSH imm8 */
+ 2|MODRM,/* B: IMUL */
+ 1, /* C: INSB */
+ 1, /* D: INSW */
+ 1, /* E: OUTSB */
+ 1, /* F: OUTSW */
+
+ /* 0x70 - 0x7F */
+ 1+1, /* 0: JO */
+ 1+1, /* 1: JNO */
+ 1+1, /* 2: JB */
+ 1+1, /* 3: JNB */
+ 1+1, /* 4: JZ */
+ 1+1, /* 5: JNZ */
+ 1+1, /* 6: JBE */
+ 1+1, /* 7: JA */
+ 1+1, /* 8: JS */
+ 1+1, /* 9: JNS */
+ 1+1, /* A: JP */
+ 1+1, /* B: JNP */
+ 1+1, /* C: JL */
+ 1+1, /* D: JNL */
+ 1+1, /* E: JLE */
+ 1+1, /* F: JNLE */
+
+ /* 0x80 - 0x8F */
+ 2|MODRM,/* 0: ADD modrm, imm8 */
+ 2|MODRM,/* 1: ADD modrm, imm8 */
+ 2|MODRM,/* 2: SUB/CMP modrm, imm8 */
+ 2|MODRM,/* 3: SUB/CMP modrm, imm8 */
+ 1|MODRM,/* 4: TEST modrm, modrm */
+ 1|MODRM,/* 5: TEST modrm, modrm */
+ 1|MODRM,/* 6: XCHG modrm, modrm */
+ 1|MODRM,/* 7: XCHG modrm, modrm */
+ 1|MODRM,/* 8: MOV modrm 8 */
+ 1|MODRM,/* 9: MOV modrm 16/32 */
+ 1|MODRM,/* A: MOV modrm 8 reverse */
+ 1|MODRM,/* B: MOV modrm 16/32 reverse */
+ 1|MODRM,/* C: MOV modrm 16 seg */
+ 1|MODRM,/* D: LEA modrm */
+ 1|MODRM,/* E: MOV modrm 16 seg reverse */
+ 1|MODRM,/* F: POP... modrm (only this indexed opcode) */
+
+ /* 0x90 - 0x9F */
+ 1, /* 0: NOP */
+ 1, /* 1: XCHG EAX, ECX */
+ 1, /* 3: XCHG EAX, EDX */
+ 1, /* 3: XCHG EAX, EBX */
+ 1, /* 4: XCHG EAX, ESP */
+ 1, /* 5: XCHG EAX, EBP */
+ 1, /* 6: XCHG EAX, ESI */
+ 1, /* 7: XCHG EAX, EDI */
+ 1, /* 8: CBW */
+ 1, /* 9: CWD */
+ 1|OPND_PP, /* A: CALL (32 or 48 bit immed ptr) */
+ 1, /* B: WAIT */
+ 1, /* C: PUSHF */
+ 1, /* D: POPF */
+ 1, /* E: SAHF */
+ 1, /* F: LAHF */
+
+ /* 0xA0 - 0xAF */
+ 1|ADDR_WD,/* 0: MOV AL,rm */
+ 1|ADDR_WD,/* 1: MOV EAX,rm */
+ 1|ADDR_WD,/* 2: MOV rm,AL */
+ 1|ADDR_WD,/* 3: MOV rm,EAX */
+ 1, /* 4: MOVSB */
+ 1, /* 5: MOVSW */
+ 1, /* 6: CMPSB */
+ 1, /* 7: CMPSW */
+ 1+1, /* 8: TEST AL, imm8 */
+ 1|OPND_WD,/* 9: TEST EAX, imm16/32 */
+ 1, /* A: STOSB */
+ 1, /* B: STOSW */
+ 1, /* C: LODSB */
+ 1, /* D: LODSW */
+ 1, /* E: SCASB */
+ 1, /* F: SCASW */
+
+ /* 0xB0 - 0xBF */
+ 1+1, /* 0: MOV AL, imm8 */
+ 1+1, /* 1: MOV CL, imm8 */
+ 1+1, /* 2: MOV DL, imm8 */
+ 1+1, /* 3: MOV BL, imm8 */
+ 1+1, /* 4: MOV AH, imm8 */
+ 1+1, /* 5: MOV CH, imm8 */
+ 1+1, /* 6: MOV DH, imm8 */
+ 1+1, /* 7: MOV BH, imm8 */
+ 1|OPND_WD,/* 8: MOV EAX, imm16/32 */
+ 1|OPND_WD,/* 9: MOV ECX, imm16/32 */
+ 1|OPND_WD,/* A: MOV EDX, imm16/32 */
+ 1|OPND_WD,/* B: MOV EBX, imm16/32 */
+ 1|OPND_WD,/* C: MOV ESP, imm16/32 */
+ 1|OPND_WD,/* D: MOV EBP, imm16/32 */
+ 1|OPND_WD,/* E: MOV ESI, imm16/32 */
+ 1|OPND_WD,/* F: MOV EDI, imm16/32 */
+
+ /* 0xC0 - 0xCF */
+ 2|MODRM,/* 0: ROL... r/m8, imm8 */
+ 2|MODRM,/* 1: ROL... r/m16/32, imm8 */
+ 1+2, /* 2: RETN */
+ 1, /* 3: RETN */
+ 1|MODRM,/* 4: LES */
+ 1|MODRM,/* 5: LDS */
+ 2|MODRM,/* 6: MOV... modrm, imm8 (only this indexed opcode) */
+ 1|MODRM|OPND_WD,/* 7: MOV... modrm, imm16/32 (only this indexed opcode) */
+ 1+2+1, /* 8: ENTER */
+ 1, /* 9: LEAVE */
+ 1+2, /* A: RETF */
+ 1, /* B: RETF */
+ 1, /* C: INT3 */
+ 1+1, /* D: INT */
+ 1, /* E: INTO */
+ 1, /* F: IRET */
+
+ /* 0xD0 - 0xDF */
+ 1|MODRM,/* 0: ROL... modrm8, 1 */
+ 1|MODRM,/* 1: ROL... modrm16/32, 1 */
+ 1|MODRM,/* 2: ROL... modrm8, CL */
+ 1|MODRM,/* 3: ROL... modrm16/32, CL */
+ 1+1, /* 4: AAM imm8 */
+ 1+1, /* 5: AAD imm8 */
+ 1, /* 6: SALC */
+ 1, /* 7: XLAT */
+ 1|MODRM,/* 8: ESC/FP */
+ 1|MODRM,/* 9: ESC/FP */
+ 1|MODRM,/* A: ESC/FP */
+ 1|MODRM,/* B: ESC/FP */
+ 1|MODRM,/* C: ESC/FP */
+ 1|MODRM,/* D: ESC/FP */
+ 1|MODRM,/* E: ESC/FP */
+ 1|MODRM,/* F: ESC/FP */
+
+ /* 0xE0 - 0xEF */
+ 1+1, /* 0: LOOPNZ */
+ 1+1, /* 1: LOOPZ */
+ 1+1, /* 2: LOOP */
+ 1+1, /* 3: JCXZ */
+ 1+1, /* 4: IN AL, imm8 */
+ 1+1, /* 5: IN EAX, imm8 */
+ 1+1, /* 6: OUT, imm8, AL */
+ 1+1, /* 7: OUT, imm8, EAX */
+ 1|OPND_WD,/* 8: CALL imm16/32 relative ptr */
+ 1|OPND_WD,/* 9: JMP imm16/32 relative ptr */
+ 1|OPND_PP,/* A: JMP (32- or 48-bit immed ptr) */
+ 1+1, /* B: JMP imm8 relative ptr */
+ 1, /* C: IN AL, DX */
+ 1, /* D: IN EAX, DX */
+ 1, /* E: OUT DX, AL */
+ 1, /* F: OUT DX, EAX */
+
+ /* 0xF0 - 0xFF */
+ PREFIX, /* 0: prefix */
+ 1, /* 1: INT1/ICEBP */
+ PREFIX, /* 2: prefix */
+ PREFIX, /* 3: prefix */
+ 1, /* 4: HLT */
+ 1, /* 5: CMC */
+ MULTI, /* 6: TEST... 8-bit */
+ MULTI, /* 7: TEST... 16/32-bit */
+ 1, /* 8: CLC */
+ 1, /* 9: STC */
+ 1, /* A: CLI */
+ 1, /* B: STI */
+ 1, /* C: CLD */
+ 1, /* D: STD */
+ 1|MODRM,/* E: INC/DEC */
+ MULTI /* F: INC/DEC/CALL/JMP/PUSH */
+};
+
+static const unsigned char opinfos_twobyte[256] = {
+ /* 0x00 - 0x0F */
+ 1|MODRM,/* 0: SLDT... */
+ 1|MODRM,/* 1: SGDT... */
+ 1|MODRM,/* 2: LAR modrm, modrm */
+ ILLEGAL,
+ ILLEGAL,
+ 1, /* 5: SYSCALL */
+ 1, /* 6: CLTS */
+ 1, /* 7: SYSRET */
+ ILLEGAL,
+ 1, /* 9: WBINVD */
+ ILLEGAL,
+ 1, /* B: UD2 */
+ ILLEGAL,
+ 1|MODRM,/* D: PREFETCHW */
+ ILLEGAL,
+ ILLEGAL,
+
+ /* 0x10 - 0x1F */
+ 1|MODRM,/* 0: MOVLPS/MOVSD/MOVSS/MOVUPS (depends on prefix) */
+ 1|MODRM,/* 1: MOVLPS/MOVSD/MOVSS/MOVUPS (depends on prefix) */
+ 1|MODRM,/* 2: MOVDDUP/MOVHLPS/MOVLPD/MOVSLDUP */
+ 1|MODRM,/* 3: MOVLDP */
+ 1|MODRM,/* 4: UNPCKLPD/UNPCKLPS */
+ 1|MODRM,/* 5: UNPCKHPD/UNPCKHPS */
+ 1|MODRM,/* 6: MOVHPD/MOVLHPS/MOVSHDUP */
+ 1|MODRM,/* 7: MOVHPD/MOVHPS */
+ 1|MODRM,/* 8: PREFETCH... */
+ 1|MODRM,/* 9: HINT NOP (?) */
+ 1|MODRM,/* A: HINT NOP (?) */
+ 1|MODRM,/* B: HINT NOP (?) */
+ 1|MODRM,/* C: HINT NOP (?) */
+ 1|MODRM,/* D: HINT NOP (?) */
+ 1|MODRM,/* E: HINT NOP (?) */
+ 1|MODRM,/* F: HINT NOP modrm */
+
+ /* 0x20 - 0x2F */
+ 1|MODRM,/* 0: MOV modrm, CRn */
+ 1|MODRM,/* 1: MOV modrm, DRn */
+ 1|MODRM,/* 2: MOV CRn, modrm */
+ 1|MODRM,/* 3: MOV DRn, modrm */
+ ILLEGAL,
+ ILLEGAL,
+ ILLEGAL,
+ ILLEGAL,
+ 1|MODRM,/* 8: MOVAPD/MOVAPS */
+ 1|MODRM,/* 9: MOVAPD/MOVAPS */
+ 1|MODRM,/* A: CVTPI2PD */
+ 1|MODRM,/* B: MOVNTPS/MOVNTPD */
+ 1|MODRM,/* C: CVTTPD2PI */
+ 1|MODRM,/* D: CVTPD2PI */
+ 1|MODRM,/* E: UCOMISD/UCOMISS */
+ 1|MODRM,/* F: COMISD/COMISS */
+
+ /* 0x30 - 0x3F */
+ 1, /* 0: WRMSR */
+ 1, /* 1: RDTSC */
+ 1, /* 2: RDMSR */
+ ILLEGAL,
+ 1, /* 4: SYSENTER */
+ 1, /* 5: SYSEXIT */
+ ILLEGAL,
+ ILLEGAL,
+ ILLEGAL, /* 8: PREFIX (not implemented) */
+ ILLEGAL,
+ ILLEGAL, /* A: PREFIX (not implemented) */
+ ILLEGAL,
+ ILLEGAL,
+ ILLEGAL,
+ ILLEGAL,
+ ILLEGAL,
+
+ /* 0x40 - 0x4F */
+ 1|OPND_WD,/* 0: CMOVO */
+ 1|OPND_WD,/* 1: CMOVNO */
+ 1|OPND_WD,/* 2: CMOVB/CMOVC/CMOVNAE */
+ 1|OPND_WD,/* 3: CMOVAE/CMOVNB/CMOVNC */
+ 1|OPND_WD,/* 4: CMOVE/CMOVZ */
+ 1|OPND_WD,/* 5: CMOVNE/CMOVNZ */
+ 1|OPND_WD,/* 6: CMOVBE/CMOVNA */
+ 1|OPND_WD,/* 7: CMOVA/CMOVNBE */
+ 1|OPND_WD,/* 8: CMOVS */
+ 1|OPND_WD,/* 9: CMOVNS */
+ 1|OPND_WD,/* A: CMOVP/CMOVPE */
+ 1|OPND_WD,/* B: CMOVNP/CMOVPO */
+ 1|OPND_WD,/* C: CMOVL/CMOVNGE */
+ 1|OPND_WD,/* D: CMOVGE/CMOVNL */
+ 1|OPND_WD,/* E: CMOVLE/CMOVNG */
+ 1|OPND_WD,/* F: CMOVG/CMOVNLE */
+
+ /* 0x50 - 0x5F */
+ 1|MODRM,/* 0: MOVMSKPS/MOVMSKPSD */
+ 1|MODRM,/* 1: SQRTPD */
+ 1|MODRM,/* 2: RSQRTPS */
+ 1|MODRM,/* 3: RCPSS */
+ 1|MODRM,/* 4: ANDPD */
+ 1|MODRM,/* 5: ANDNPD */
+ 1|MODRM,/* 6: ORPD */
+ 1|MODRM,/* 7: XORPD */
+ 1|MODRM,/* 8: ADDPD */
+ 1|MODRM,/* 9: MULPD */
+ 1|MODRM,/* A: CVTPD2PS/CVTSD2SS */
+ 1|MODRM,/* B: CVTPS2DQ/CVTTPS2DQ */
+ 1|MODRM,/* C: SUBPD */
+ 1|MODRM,/* D: MINPD/MINSD/MINSS */
+ 1|MODRM,/* E: DIVPD/DIVSD/DIVSS */
+ 1|MODRM,/* F: MAXPD/MAXSD/MAXSS */
+
+ /* 0x60 - 0x6F */
+ 1|MODRM,/* 0: PUNPCKLBW */
+ 1|MODRM,/* 1: PUNPCKLWD */
+ 1|MODRM,/* 2: PUNPCKLDQ */
+ 1|MODRM,/* 3: PACKSSWB */
+ 1|MODRM,/* 4: PCMPGTB */
+ 1|MODRM,/* 5: PCMPGTW */
+ 1|MODRM,/* 6: PCMPGTD */
+ 1|MODRM,/* 7: PACKUSWB */
+ 1|MODRM,/* 8: PUNPCKHBW */
+ 1|MODRM,/* 9: PUNPCKHWD */
+ 1|MODRM,/* A: PUNPCKHDQ */
+ 1|MODRM,/* B: PACKSSDW */
+ 1|MODRM,/* C: PUNPCKLQDQ */
+ 1|MODRM,/* D: PUNPCKHQDQ */
+ 1|MODRM,/* E: MOVD */
+ 1|MODRM,/* F: MOVDQA/MOVDQU/MOVQ */
+
+ /* 0x70 - 0x7F */
+ 2|MODRM,/* 0: PSHUFD */
+ 2|MODRM,/* 1: PSLLW */
+ 2|MODRM,/* 2: PSLLD */
+ 2|MODRM,/* 3: PSLLQ */
+ 1|MODRM,/* 4: PCMPEQB */
+ 1|MODRM,/* 5: PCMPEQW */
+ 1|MODRM,/* 6: PCMPEQD */
+ 1, /* 7: EMMS */
+ ILLEGAL,
+ ILLEGAL,
+ ILLEGAL,
+ ILLEGAL,
+ 1|MODRM,/* C: HADDPD */
+ 1|MODRM,/* D: HSUBPD */
+ 1|MODRM,/* E: MOVD */
+ 1|MODRM,/* F: MOVDQA/MOVDQU/MOVQ */
+
+ /* 0x80 - 0x8F */
+ 1|OPND_WD,/* 0: JO */
+ 1|OPND_WD,/* 1: JNO */
+ 1|OPND_WD,/* 2: JB/JC/JNAE */
+ 1|OPND_WD,/* 3: JAE/JNB/JNC */
+ 1|OPND_WD,/* 4: JE/JZ */
+ 1|OPND_WD,/* 5: JNE/JNZ */
+ 1|OPND_WD,/* 6: JBE/JNA */
+ 1|OPND_WD,/* 7: JA/JNBE */
+ 1|OPND_WD,/* 8: JS */
+ 1|OPND_WD,/* 9: JNS */
+ 1|OPND_WD,/* A: JP/JPE */
+ 1|OPND_WD,/* B: JNP/JPO */
+ 1|OPND_WD,/* C: JL/JNGE */
+ 1|OPND_WD,/* D: JGE/JNL */
+ 1|OPND_WD,/* E: JLE/JNG */
+ 1|OPND_WD,/* F: JG/JNLE */
+
+ /* 0x90 - 0x9F */
+ 1|OPND_WD,/* 0: SETO */
+ 1|OPND_WD,/* 1: SETNO */
+ 1|OPND_WD,/* 2: SETB/SETC/SETNAE */
+ 1|OPND_WD,/* 3: SETAE/SETNB/SETNC */
+ 1|OPND_WD,/* 4: SETE/SETZ */
+ 1|OPND_WD,/* 5: SETNE/SETNZ */
+ 1|OPND_WD,/* 6: SETBE/SETNA */
+ 1|OPND_WD,/* 7: SETA/SETNBE */
+ 1|OPND_WD,/* 8: SETS */
+ 1|OPND_WD,/* 9: SETNS */
+ 1|OPND_WD,/* A: SETP/SETPE */
+ 1|OPND_WD,/* B: SETNP/SETPO */
+ 1|OPND_WD,/* C: SETL/SETNGE */
+ 1|OPND_WD,/* D: SETGE/SETNL */
+ 1|OPND_WD,/* E: SETLE/SETNG */
+ 1|OPND_WD,/* F: SETG/SETNLE */
+
+ /* 0xA0 - 0xAF */
+ 1, /* 0: PUSH FS */
+ 1, /* 1: POP FS */
+ 1, /* 2: CPUID */
+ 1|MODRM,/* 3: BT modrm */
+ 2|MODRM,/* 4: SHLD modrm, imm8 */
+ 1|MODRM,/* 5: SHLD modrm, CL */
+ ILLEGAL,
+ ILLEGAL,
+ 1, /* 8: PUSH GS */
+ 1, /* 9: POP GS */
+ 1, /* A: RSM */
+ 1|MODRM,/* B: BTS modrm */
+ 2|MODRM,/* C: SHRD modrm, imm8 */
+ 1|MODRM,/* D: SHRD modrm, CL */
+ /*2,*/ /* E: SFENCE/LFENCE/MFENCE(?) */
+ 1|MODRM,/* E: FXSAVE... */
+ 1|MODRM,/* F: IMUL modrm, modrm */
+
+ /* 0xB0 - 0xBF */
+ 1|MODRM,/* 0: CMPXCHG modrm, modrm */
+ 1|MODRM,/* 1: CMPXCHG modrm, modrm */
+ 1|MODRM,/* 2: LSS modrm, modrm */
+ 1|MODRM,/* 3: BTR modrm */
+ 1|MODRM,/* 4: LFS modrm, modrm */
+ 1|MODRM,/* 5: LGS modrm, modrm */
+ 1|MODRM,/* 6: MOVZX modrm, modrm */
+ 1|MODRM,/* 7: MOVZX modrm, modrm */
+ 1|MODRM,/* 8: POPCNT modrm, modrm */
+ 1, /* 9: UD (?) */
+ 1|MODRM,/* A: BTx... modrm, imm8 */
+ 1|MODRM,/* B: BTC modrm */
+ 1|MODRM,/* C: BSF modrm, modrm */
+ 1|MODRM,/* D: BSR modrm, modrm */
+ 1|MODRM,/* E: MOVSX modrm, modrm */
+ 1|MODRM,/* F: MOVSX modrm, modrm */
+
+ /* 0xC0 - 0xCF */
+ 1|MODRM,/* 0: XADD modrm, modrm */
+ 1|MODRM,/* 1: XADD modrm, modrm */
+ 2|MODRM,/* 5: CMPPD */
+ 1|MODRM,/* 3: MOVNTI */
+ 2|MODRM,/* 4: PINSRW */
+ 2|MODRM,/* 5: PEXTRW */
+ 2|MODRM,/* 6: SHUFPS */
+ 1|MODRM,/* 7: CMPXCHGxB... modrm */
+ 1, /* 8: BSWAP EAX */
+ 1, /* 9: BSWAP ECX */
+ 1, /* A: BSWAP EDX */
+ 1, /* B: BSWAP EBX */
+ 1, /* C: BSWAP ESP */
+ 1, /* D: BSWAP EBP */
+ 1, /* E: BSWAP ESI */
+ 1, /* F: BSWAP EDI */
+
+
+ /* 0xD0 - 0xDF */
+ 1|MODRM,/* 0: ADDSUBPD */
+ 1|MODRM,/* 1: PSRLW */
+ 1|MODRM,/* 2: PSRLD */
+ 1|MODRM,/* 3: PSRLQ */
+ 1|MODRM,/* 4: PADDQ */
+ 1|MODRM,/* 5: PMULLW */
+ 1|MODRM,/* 6: MOVDQ2Q/MOVQ/MOVQ2DQ */
+ 1|MODRM,/* 7: PMOVMSKB */
+ 1|MODRM,/* 8: PSUBUSB modrm */
+ 1|MODRM,/* 9: PSUBUSW modrm */
+ 1|MODRM,/* A: PMINUB */
+ 1|MODRM,/* B: PAND */
+ 1|MODRM,/* C: PADDUSB */
+ 1|MODRM,/* D: PADDUSW */
+ 1|MODRM,/* E: PMAXUB */
+ 1|MODRM,/* F: PANDN */
+
+ /* 0xE0 - 0xEF */
+ 1|MODRM,/* 0: PAVGB */
+ 1|MODRM,/* 1: PSRAW */
+ 1|MODRM,/* 2: PSRAD */
+ 1|MODRM,/* 3: PAVGW */
+ 1|MODRM,/* 4: PMULHUW */
+ 1|MODRM,/* 5: PMULHW */
+ 1|MODRM,/* 6: CVTDQ2PD */
+ 1|MODRM,/* 7: MOVNTQ/MOVNTDQ */
+ 1|MODRM,/* 8: PSUBSB modrm */
+ 1|MODRM,/* 9: PSUBSW modrm */
+ 1|MODRM,/* A: PMINSW */
+ 1|MODRM,/* B: POR */
+ 1|MODRM,/* C: PADDSB */
+ 1|MODRM,/* D: PADDSW */
+ 1|MODRM,/* E: PMAXSW */
+ 1|MODRM,/* F: PXOR */
+
+ /* 0xF0 - 0xFF */
+ 1|MODRM,/* 0: MOVBE (with prefix after 0x0F/TWOBYTE), LDDQU */
+ 1|MODRM,/* 1: PSLLW */
+ 1|MODRM,/* 2: PSLLD */
+ 1|MODRM,/* 3: PSLLQ */
+ 1|MODRM,/* 4: PMULUDQ */
+ 1|MODRM,/* 5: PMADDWD */
+ 1|MODRM,/* 6: PSADBW */
+ 1|MODRM,/* 7: MASKMOVQ */
+ 1|MODRM,/* 8: PSUBB */
+ 1|MODRM,/* 9: PSUBW */
+ 1|MODRM,/* A: PSUBD */
+ 1|MODRM,/* B: PSUBQ */
+ 1|MODRM,/* C: PADDB */
+ 1|MODRM,/* D: PADDW */
+ 1|MODRM,/* E: PADDD */
+ ILLEGAL
+};
+
+static unsigned char get_modrm_extra(int is16, int mod, int rm)
+{
+ if (is16) {
+ switch (mod) {
+ case 0: return (rm == 0x6 ? 2 : 0);
+ case 1: return 1;
+ case 2: return 2;
+ case 3: return 0;
+ }
+ } else {
+ int sib = (rm == 0x4 ? 1 : 0);
+ switch (mod) {
+ case 0: return (rm == 0x5 ? 4 : sib);
+ case 1: return sib+1;
+ case 2: return sib+4;
+ case 3: return 0;
+ }
+ }
+}
+
+/* Instructions with only one format are not handled here:
+ 80, 81, 83, 8F, C1, C6, C7, D1, D2, D3, D8...DF, FE,
+ 0F_00, 0F_01, 0F_18, 0F_1F_ 0F_AE, 0F_BA, 0F_C7 */
+static unsigned char get_idx_opinfo(unsigned char opc, unsigned char idx)
+{
+ switch (opc<<4 | idx) {
+ case 0xF60: /* TEST */
+ return 2|MODRM;
+ /* is there an F6 /1 ? */
+ case 0xF62: /* NOT */
+ case 0xF63: /* NEG */
+ case 0xF64: /* IMUL */
+ case 0xF65: /* IMUL */
+ case 0xF66: /* DIV */
+ case 0xF67: /* IDIV */
+ return 1|MODRM;
+
+ case 0xF70: /* TEST */
+ return 1|MODRM|OPND_WD;
+ /* is there an F7 /1 ? */
+ case 0xF72: /* NOT */
+ case 0xF73: /* NEG */
+ case 0xF74: /* IMUL */
+ case 0xF75: /* IMUL */
+ case 0xF76: /* DIV */
+ case 0xF77: /* IDIV */
+ return 1|MODRM;
+
+ case 0xFF0: /* INC */
+ case 0xFF1: /* DEC */
+ case 0xFF2: /* CALL */
+ case 0xFF3: /* CALL */
+ case 0xFF4: /* JMP */
+ return 1|MODRM;
+ case 0xFF5: /* JMP */
+ return 1|MODRM|OPND_WD;
+ case 0xFF6: /* PUSH */
+ return 1|MODRM;
+ default:
+ return ILLEGAL;
+ }
+}
+
+unsigned char get_x86_instr_size(const unsigned char *code, unsigned long start, unsigned long codelen)
+{
+ const char *p, *end;
+ BYTE c;
+ BYTE opinfo;
+ int opnd16 = 0, addr16 = 0;
+ BYTE instrlen = 0;
+
+ if (start >= codelen) return 0;
+ p = &code[start];
+ end = &code[codelen];
+
+ /* Prefixes */
+ for (;;) {
+ c = *p;
+ opinfo = opinfos[c];
+ if (opinfo != PREFIX) break;
+ if (c == 0x66) {
+ if (!opnd16) opnd16 = 1;
+ else return ILLEGAL_INSTR_SIZE;
+ }
+ if (c == 0x67) {
+ if (!addr16) addr16 = 1;
+ else return ILLEGAL_INSTR_SIZE;
+ }
+ instrlen++;
+ if (++p >= end) return ILLEGAL_INSTR_SIZE;
+ }
+
+ /* Opcode */
+ if (opinfo == TWOBYTE) {
+ if (++p >= end) return ILLEGAL_INSTR_SIZE;
+ c = *p;
+ opinfo = opinfos_twobyte[c];
+ if (opinfo == ILLEGAL) return ILLEGAL_INSTR_SIZE;
+ instrlen++;
+ }
+
+ if (opinfo == MULTI) {
+ /* Instruction index in Mod-R/M */
+ BYTE opc = c, idx;
+ if (++p >= end) return ILLEGAL_INSTR_SIZE;
+ c = *p;
+ instrlen += 1 + get_modrm_extra(opnd16, (int)c>>6, c&0x7);
+ idx = (c&0x38)>>3;
+ opinfo = get_idx_opinfo(opc, idx);
+ } else if ((opinfo & MODRM) != 0) {
+ /* Normal Mod-R/M */
+ if (++p >= end) return ILLEGAL_INSTR_SIZE;
+ c = *p;
+ instrlen += 1 + get_modrm_extra(opnd16, (int)c>>6, c&0x7);
+ }
+
+ /* Variable size (16/32/48) arguments */
+ switch (opinfo & OPNDADDRMASK) {
+ case OPND_WD: instrlen += (opnd16 ? 2 : 4); break;
+ case OPND_PP: instrlen += (opnd16 ? 2 : 4); break;
+ case ADDR_WD: instrlen += (addr16 ? 2 : 4); break;
+ default: ;
+ }
+
+ /* Add size of opcode + size of immediate operands */
+ instrlen += opinfo & 0xF;
+ return instrlen;
+}
+
+
diff --git a/HitTrace/x86ops.h b/HitTrace/x86ops.h new file mode 100644 index 0000000..462b3a7 --- /dev/null +++ b/HitTrace/x86ops.h @@ -0,0 +1,30 @@ +/*
+
+ Copyright (c) 2014-2015 Samuel Lidén Borell <samuel@kodafritt.se>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+*/
+
+#ifndef X86OPS_H
+#define X86OPS_H
+
+unsigned char get_x86_instr_size(const unsigned char *code, unsigned long start, unsigned long codelen);
+
+#endif
|