mirror of
https://github.com/HIllya51/LunaTranslator.git
synced 2024-12-28 08:04:13 +08:00
depracated
1 1
This commit is contained in:
parent
1a8dd9d3bf
commit
16310b2218
@ -11,7 +11,6 @@ from gui.showword import searchwordW
|
||||
from myutils.hwnd import pid_running,getpidexe ,testprivilege,ListProcess
|
||||
from textsource.copyboard import copyboard
|
||||
from textsource.texthook import texthook
|
||||
from textsource.fridahook import fridahook
|
||||
from textsource.ocrtext import ocrtext
|
||||
import gui.selecthook
|
||||
import gui.translatorUI
|
||||
@ -349,26 +348,17 @@ class MAINUI() :
|
||||
pids,pexe,hwnd=( selectedp)
|
||||
checkifnewgame(pexe,windows.GetWindowText(hwnd))
|
||||
if globalconfig['sourcestatus2']['texthook']['use']:
|
||||
self.textsource=texthook(pids,hwnd,pexe)
|
||||
elif globalconfig['sourcestatus2']['fridahook']['use']:
|
||||
if len(pids)!=1:
|
||||
getQMessageBox(self.settin_ui,"错误","Only support pid num of 1")
|
||||
return
|
||||
try:
|
||||
self.textsource=fridahook(0,self.settin_ui.fridascripts[self.settin_ui.Scriptscombo.currentIndex()],pexe,pids[0])
|
||||
except:
|
||||
print_exc()
|
||||
|
||||
self.textsource=texthook(pids,hwnd,pexe)
|
||||
|
||||
#@threader
|
||||
def starttextsource(self,use=None,checked=True):
|
||||
self.translation_ui.showhidestate=False
|
||||
self.translation_ui.refreshtooliconsignal.emit()
|
||||
self.settin_ui.selectbutton.setEnabled(globalconfig['sourcestatus2']['texthook']['use'] or globalconfig['sourcestatus2']['fridahook']['use'])
|
||||
self.settin_ui.selectbutton.setEnabled(globalconfig['sourcestatus2']['texthook']['use'])
|
||||
self.settin_ui.selecthookbutton.setEnabled(globalconfig['sourcestatus2']['texthook']['use'] )
|
||||
self.textsource=None
|
||||
if checked:
|
||||
classes={'ocr':ocrtext,'copy':copyboard,'texthook':None,'fridahook':None}
|
||||
classes={'ocr':ocrtext,'copy':copyboard,'texthook':None}
|
||||
if use is None:
|
||||
use=list(filter(lambda _ :globalconfig['sourcestatus2'][_]['use'],classes.keys()) )
|
||||
use=None if len(use)==0 else use[0]
|
||||
@ -469,7 +459,7 @@ class MAINUI() :
|
||||
|
||||
|
||||
def onwindowloadautohook(self):
|
||||
textsourceusing=globalconfig['sourcestatus2']['texthook']['use'] or globalconfig['sourcestatus2']['fridahook']['use']
|
||||
textsourceusing=globalconfig['sourcestatus2']['texthook']['use']
|
||||
if not(globalconfig['autostarthook'] and textsourceusing):
|
||||
return
|
||||
elif self.AttachProcessDialog.isVisible():
|
||||
@ -493,9 +483,6 @@ class MAINUI() :
|
||||
savehook_new_list.insert(0,savehook_new_list.pop(idx))
|
||||
needinserthookcode=savehook_new_data[name_]['needinserthookcode']
|
||||
self.textsource=texthook(pids,hwnd,name_ ,autostarthookcode=savehook_new_data[name_]['hook'],needinserthookcode=needinserthookcode)
|
||||
elif len(pids)==1 and globalconfig['sourcestatus2']['fridahook']['use'] and savehook_new_data[name_]['fridahook']['loadmethod']==0:
|
||||
self.textsource=fridahook(0,savehook_new_data[name_]['fridahook']['js'],name_,pids[0],hwnd)
|
||||
|
||||
|
||||
onloadautoswitchsrclang=savehook_new_data[name_]['onloadautoswitchsrclang']
|
||||
if onloadautoswitchsrclang>0:
|
||||
|
@ -31,11 +31,7 @@ def overridepathexists():
|
||||
PathFileExists.restype=wintypes.BOOL
|
||||
#win7上,如果假如没有D盘,然后os.path.exists("D:/..."),就会弹窗说不存在D盘
|
||||
os.path.exists=lambda file:bool(PathFileExists(os.path.abspath(file)))
|
||||
_jsconsole=debugoutput('jsconsole',sys.stdout)
|
||||
|
||||
def overridestdio():
|
||||
sys.stderr=debugoutput('stderr',sys.stderr)
|
||||
sys.stdout=debugoutput('stdout',sys.stdout)
|
||||
def gprint(*args,**kwargs):
|
||||
kwargs['file']=_jsconsole
|
||||
print(*args,**kwargs)
|
||||
|
||||
|
@ -15,7 +15,6 @@ from PyQt5.QtCore import Qt
|
||||
from gui.usefulwidget import getsimplecombobox,getspinbox,getcolorbutton,getsimpleswitch,getspinbox,selectcolor
|
||||
from PyQt5.QtCore import QPoint, QRect, QSize, Qt,pyqtSignal
|
||||
import os
|
||||
from textsource.fridahook import fridahook
|
||||
from myutils.hwnd import showintab,getScreenRate
|
||||
from PyQt5.QtGui import QStandardItem, QStandardItemModel
|
||||
from PyQt5.QtCore import Qt,QSize
|
||||
@ -25,7 +24,7 @@ import gobject
|
||||
from myutils.config import _TR,_TRL,globalconfig,static_data
|
||||
import winsharedutils
|
||||
from myutils.wrapper import Singleton_close,Singleton,threader
|
||||
from myutils.utils import checkifnewgame ,loadfridascriptslist
|
||||
from myutils.utils import checkifnewgame
|
||||
from myutils.proxy import getproxy
|
||||
from gui.usefulwidget import yuitsu_switch,saveposwindow,getboxlayout
|
||||
from myutils.vndb import parsehtmlmethod
|
||||
@ -502,7 +501,7 @@ class dialog_setting_game(QDialog):
|
||||
|
||||
formLayout.addLayout(getboxlayout([
|
||||
QLabel(_TR("自动切换到模式")),
|
||||
getsimplecombobox(_TRL(['不切换','HOOK','剪贴板','OCR','FridaHook']),savehook_new_data[exepath],'onloadautochangemode2')
|
||||
getsimplecombobox(_TRL(['不切换','HOOK','剪贴板','OCR']),savehook_new_data[exepath],'onloadautochangemode2')
|
||||
]))
|
||||
|
||||
formLayout.addLayout(getboxlayout([
|
||||
@ -513,7 +512,6 @@ class dialog_setting_game(QDialog):
|
||||
|
||||
methodtab=QTabWidget()
|
||||
methodtab.addTab(self.gethooktab(exepath),"HOOK")
|
||||
methodtab.addTab(self.getfridatab(exepath),"FridaHook")
|
||||
methodtab.addTab(self.getpretranstab(exepath),"预翻译")
|
||||
formLayout.addWidget(methodtab)
|
||||
|
||||
@ -542,31 +540,7 @@ class dialog_setting_game(QDialog):
|
||||
getcolorbutton('','',functools.partial(selectimg,key,filt,editjson),icon='fa.gear',constcolor="#FF69B4")
|
||||
]))
|
||||
return _w
|
||||
def getfridatab(self,exepath):
|
||||
_w=QWidget()
|
||||
formLayout = QVBoxLayout()
|
||||
formLayout.setAlignment(Qt.AlignTop)
|
||||
_w.setLayout(formLayout)
|
||||
Scriptscombo=QComboBox()
|
||||
Scriptscombo.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
|
||||
fridascripts=loadfridascriptslist(globalconfig['fridahook']['path'],Scriptscombo)
|
||||
fridahook=savehook_new_data[exepath]['fridahook']
|
||||
try:
|
||||
Scriptscombo.setCurrentIndex(fridascripts.index(fridahook['js']))
|
||||
except:
|
||||
Scriptscombo.setCurrentIndex(0)
|
||||
Scriptscombo.currentTextChanged.connect(lambda text:fridahook.__setitem__('js',text))
|
||||
wids=[QLabel('Scripts'),Scriptscombo]
|
||||
wids[0].setFixedWidth(100)
|
||||
formLayout.addLayout(getboxlayout(wids))
|
||||
|
||||
formLayout.addLayout(getboxlayout([
|
||||
QLabel('Load Method'),
|
||||
getsimplecombobox(['Attach','Spawn'],fridahook,'loadmethod')
|
||||
]))
|
||||
|
||||
|
||||
return _w
|
||||
|
||||
def gethooktab(self,exepath):
|
||||
_w=QWidget()
|
||||
formLayout = QVBoxLayout()
|
||||
@ -693,17 +667,13 @@ def startgame(game):
|
||||
_={
|
||||
1:'texthook',
|
||||
2:'copy',
|
||||
3:'ocr',
|
||||
4:'fridahook'
|
||||
3:'ocr'
|
||||
}
|
||||
if globalconfig['sourcestatus2'][_[mode]]['use']==False:
|
||||
globalconfig['sourcestatus2'][_[mode]]['use']=True
|
||||
|
||||
yuitsu_switch(gobject.baseobject.settin_ui,globalconfig['sourcestatus2'],'sourceswitchs',_[mode],None ,True)
|
||||
gobject.baseobject.starttextsource(use=_[mode],checked=True)
|
||||
if globalconfig['sourcestatus2']['fridahook']['use'] and savehook_new_data[game]['fridahook'].get('loadmethod')==1:
|
||||
gobject.baseobject.textsource=fridahook(1,savehook_new_data[game]['fridahook'].get('js'),game)
|
||||
return
|
||||
|
||||
dirpath=os.path.dirname(game)
|
||||
|
||||
|
@ -1,20 +1,18 @@
|
||||
|
||||
import functools,os,shutil,windows,json
|
||||
from PyQt5.QtGui import QFont,QStandardItem,QStandardItemModel
|
||||
from PyQt5.QtGui import QFont
|
||||
from PyQt5.QtCore import Qt,QSize
|
||||
from traceback import print_exc
|
||||
from PyQt5.QtWidgets import QFontComboBox,QDialog,QLabel,QComboBox,QPushButton,QFileDialog,QFormLayout,QDialogButtonBox,QHeaderView,QHBoxLayout,QLineEdit
|
||||
from PyQt5.QtWidgets import QFontComboBox,QDialog,QLabel,QComboBox,QPushButton,QFileDialog,QFormLayout,QDialogButtonBox
|
||||
from gui.pretransfile import sqlite2json2
|
||||
from gui.settingpage_ocr import getocrgrid
|
||||
from myutils.config import globalconfig ,_TR,_TRL,savehook_new_data,savehook_new_list
|
||||
from gui.dialog_savedgame import dialog_savedgame
|
||||
import threading,gobject,requests,datetime,zipfile
|
||||
from gui.inputdialog import autoinitdialog,regexedit
|
||||
from gui.usefulwidget import getsimplecombobox,getspinbox,getcolorbutton,yuitsu_switch,getsimpleswitch,Singleton,getQMessageBox
|
||||
import gobject
|
||||
from gui.inputdialog import regexedit
|
||||
from gui.usefulwidget import getsimplecombobox,getspinbox,getcolorbutton,yuitsu_switch,getsimpleswitch
|
||||
from gui.codeacceptdialog import codeacceptdialog
|
||||
from textsource.fridahook import fridahook
|
||||
from myutils.utils import loadfridascriptslist,checkifnewgame,makehtml,getfilemd5
|
||||
from myutils.proxy import getproxy
|
||||
from myutils.utils import makehtml,getfilemd5
|
||||
def gethookgrid(self) :
|
||||
|
||||
grids=[
|
||||
@ -37,98 +35,7 @@ def gethookgrid(self) :
|
||||
]
|
||||
|
||||
return grids
|
||||
updatelock=threading.Lock()
|
||||
def updatescripts( self):
|
||||
if globalconfig['fridahook']['autoupdate']==False:return
|
||||
if updatelock.locked():return
|
||||
updatelock.acquire()
|
||||
if (os.path.exists(os.path.join(globalconfig['fridahook']['path'],'runtime/x86/frida')) or os.path.exists(os.path.join(globalconfig['fridahook']['path'],'runtime/x64/frida')))==False:return
|
||||
info_url='https://api.github.com/repos/0xDC00/scripts'
|
||||
scripts_url = f'https://api.github.com/repos/0xDC00/scripts/zipball'
|
||||
updated_at = requests.get(info_url ,proxies=getproxy()).json()['pushed_at']
|
||||
updatetimef=os.path.join(globalconfig['fridahook']['path'],'updatetime.txt')
|
||||
savezip=os.path.join(globalconfig['fridahook']['path'],'latest.zip')
|
||||
scriptspath=os.path.join(globalconfig['fridahook']['path'],'scripts')
|
||||
timefmt=lambda s:datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ").timestamp()
|
||||
dt = timefmt(updated_at )
|
||||
#print(updated_at,dt)
|
||||
try:
|
||||
with open(updatetimef,'r') as ff:
|
||||
time=ff.read()
|
||||
if timefmt(time)<dt:
|
||||
need=True
|
||||
else:
|
||||
need=False
|
||||
except:
|
||||
need=True
|
||||
print_exc()
|
||||
#print(need)
|
||||
try:
|
||||
if need:
|
||||
response = requests.get(scripts_url ,proxies=getproxy()).content
|
||||
with open(savezip,'wb') as ff:
|
||||
ff.write(response)
|
||||
zipf=(zipfile.ZipFile(savezip))
|
||||
zipf.extractall(globalconfig['fridahook']['path'])
|
||||
try:
|
||||
shutil.rmtree(scriptspath)
|
||||
except:
|
||||
pass
|
||||
os.rename(os.path.join( globalconfig['fridahook']['path'],zipf.namelist()[0]),scriptspath)
|
||||
|
||||
with open(updatetimef,'w') as ff:
|
||||
ff.write(updated_at)
|
||||
flashcombo(self,0)
|
||||
except:
|
||||
print_exc()
|
||||
updatelock.release()
|
||||
def flashcombo(self,update=1):
|
||||
self.fridascripts=loadfridascriptslist(globalconfig['fridahook']['path'],self.Scriptscombo)
|
||||
if update:
|
||||
threading.Thread(target=updatescripts,args=(self,)).start()
|
||||
def getfridahookgrid(self) :
|
||||
|
||||
|
||||
_items=[
|
||||
{'t':'file','dir':True, 'l':'FridaHook_路径','d':globalconfig['fridahook'],'k':'path'},
|
||||
{'t':'okcancel','callback':functools.partial(flashcombo,self,1)},
|
||||
]
|
||||
attachbutton=QPushButton('Attach')
|
||||
execbutton=QPushButton('Spawn')
|
||||
def execclicked():
|
||||
|
||||
f=QFileDialog.getOpenFileName(filter='*.exe')
|
||||
pname=f[0]
|
||||
if pname!='':
|
||||
pname=pname.replace('/','\\')
|
||||
checkifnewgame(pname)
|
||||
yuitsu_switch(gobject.baseobject.settin_ui,globalconfig['sourcestatus2'],'sourceswitchs','fridahook',None ,True)
|
||||
gobject.baseobject.starttextsource(use='fridahook',checked=True)
|
||||
try:
|
||||
gobject.baseobject.textsource=fridahook(1,self.fridascripts[self.Scriptscombo.currentIndex()],pname)
|
||||
except:
|
||||
print_exc()
|
||||
|
||||
execbutton.clicked.connect(execclicked)
|
||||
attachbutton.clicked.connect(gobject.baseobject.AttachProcessDialog.showsignal.emit)
|
||||
grids=[
|
||||
|
||||
[('FridaHook_路径',3),(getcolorbutton(globalconfig,'',callback=functools.partial(autoinitdialog,self, 'FridaHook_路径',800,_items),icon='fa.gear',constcolor="#FF69B4"))],
|
||||
[('下载',3),(makehtml("https://github.com/HIllya51/RESOURCES/releases/download/dictionary/FridaHook.zip",True),3,'link')],
|
||||
[],
|
||||
|
||||
[('Scripts',3),(self.Scriptscombo,10)],
|
||||
[(attachbutton,3),(execbutton,3)] ,
|
||||
[],
|
||||
[('autoupdate',3),getsimpleswitch( globalconfig['fridahook'],'autoupdate' )],
|
||||
[],
|
||||
|
||||
|
||||
[('latest scripts',3),(makehtml("https://github.com/0xDC00/scripts"),6,'link')],
|
||||
[('capable emulator',3),(makehtml("https://github.com/koukdw/emulators/releases"),6,"link")]
|
||||
]
|
||||
|
||||
return grids
|
||||
|
||||
def doexportchspatch(exe,realgame):
|
||||
|
||||
@ -257,8 +164,6 @@ def setTabOne_direct(self) :
|
||||
],
|
||||
[
|
||||
('HOOK',3),(getsimpleswitch(globalconfig['sourcestatus2']['texthook'],'use',name='texthook',parent=self,callback= functools.partial(yuitsu_switch,self,globalconfig['sourcestatus2'],'sourceswitchs','texthook',gobject.baseobject.starttextsource),pair='sourceswitchs'),1), '',
|
||||
('FridaScripts',3),(getsimpleswitch(globalconfig['sourcestatus2']['fridahook'],'use',name='fridahook',parent=self,callback= functools.partial(yuitsu_switch,self,globalconfig['sourcestatus2'],'sourceswitchs','fridahook',gobject.baseobject.starttextsource),pair='sourceswitchs'),1),
|
||||
|
||||
|
||||
] ,
|
||||
]
|
||||
@ -273,7 +178,6 @@ def setTabOne_direct(self) :
|
||||
self.threshold2label=QLabel()
|
||||
|
||||
self.Scriptscombo=QComboBox()
|
||||
flashcombo(self,1)
|
||||
def setTabOne(self) :
|
||||
self.tabadd_lazy(self.tab_widget, ('文本输入'), lambda :setTabOne_lazy(self))
|
||||
|
||||
@ -281,13 +185,12 @@ def setTabOne_lazy(self) :
|
||||
|
||||
|
||||
|
||||
tab=self.makesubtab_lazy(['HOOK设置','OCR设置','剪贴板','内嵌翻译','FridaScripts'],
|
||||
tab=self.makesubtab_lazy(['HOOK设置','OCR设置','剪贴板','内嵌翻译'],
|
||||
[
|
||||
lambda:self.makescroll(self.makegrid(gethookgrid(self))),
|
||||
lambda:self.makescroll(self.makegrid(getocrgrid(self))),
|
||||
lambda:self.makescroll(self.makegrid(setTabclip(self))),
|
||||
lambda:self.makescroll(self.makegrid(gethookembedgrid(self) )),
|
||||
lambda:self.makescroll(self.makegrid(getfridahookgrid(self) ))
|
||||
])
|
||||
|
||||
gridlayoutwidget=self.makegrid(self.tab1grids )
|
||||
|
@ -43,7 +43,7 @@ class transhist(closeashidewindow):
|
||||
self.textOutput=gettb(1)
|
||||
self.tabwidget.addTab(self.textOutput,_TR("历史翻译"))
|
||||
self.debugoutputs={}
|
||||
for _text in ['stderr','stdout','jsconsole']:
|
||||
for _text in ['stderr','stdout']:
|
||||
_x=gettb(0)
|
||||
self.tabwidget.addTab(_x,_TR(_text))
|
||||
self.debugoutputs[_text]=(_x)
|
||||
|
@ -70,7 +70,6 @@ def getdefaultsavehook(gamepath,title=None):
|
||||
"allow_tts_auto_names":'',
|
||||
"hooktypeasname":{},
|
||||
"use_saved_text_process":False,
|
||||
"fridahook":{},
|
||||
"searchnoresulttime":0,
|
||||
'relationlinks':[],
|
||||
'gamejsonfile':'',
|
||||
|
@ -1,362 +0,0 @@
|
||||
from __future__ import print_function
|
||||
from collections import OrderedDict
|
||||
try:
|
||||
from collections.abc import MutableMapping, Iterable
|
||||
except ImportError:
|
||||
from collections import MutableMapping, Iterable
|
||||
from json import dumps
|
||||
from pprint import pprint
|
||||
from sys import version_info
|
||||
from inspect import ismethod
|
||||
|
||||
# for debugging
|
||||
def here(item=None):
|
||||
out = 'here'
|
||||
if item != None:
|
||||
out += '({})'.format(item)
|
||||
print(out)
|
||||
|
||||
__all__ = ['DotMap']
|
||||
|
||||
class DotMap(MutableMapping, OrderedDict):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._map = OrderedDict()
|
||||
self._dynamic = kwargs.pop('_dynamic', True)
|
||||
self._prevent_method_masking = kwargs.pop('_prevent_method_masking', False)
|
||||
|
||||
_key_convert_hook = kwargs.pop('_key_convert_hook', None)
|
||||
trackedIDs = kwargs.pop('_trackedIDs', {})
|
||||
|
||||
if args:
|
||||
d = args[0]
|
||||
# for recursive assignment handling
|
||||
trackedIDs[id(d)] = self
|
||||
|
||||
src = []
|
||||
if isinstance(d, MutableMapping):
|
||||
src = self.__call_items(d)
|
||||
elif isinstance(d, Iterable):
|
||||
src = d
|
||||
|
||||
for k,v in src:
|
||||
if self._prevent_method_masking and k in reserved_keys:
|
||||
raise KeyError('"{}" is reserved'.format(k))
|
||||
if _key_convert_hook:
|
||||
k = _key_convert_hook(k)
|
||||
if isinstance(v, dict):
|
||||
idv = id(v)
|
||||
if idv in trackedIDs:
|
||||
v = trackedIDs[idv]
|
||||
else:
|
||||
trackedIDs[idv] = v
|
||||
v = self.__class__(v, _dynamic=self._dynamic, _prevent_method_masking = self._prevent_method_masking, _key_convert_hook =_key_convert_hook, _trackedIDs = trackedIDs)
|
||||
if type(v) is list:
|
||||
l = []
|
||||
for i in v:
|
||||
n = i
|
||||
if isinstance(i, dict):
|
||||
idi = id(i)
|
||||
if idi in trackedIDs:
|
||||
n = trackedIDs[idi]
|
||||
else:
|
||||
trackedIDs[idi] = i
|
||||
n = self.__class__(i, _dynamic=self._dynamic, _key_convert_hook =_key_convert_hook, _prevent_method_masking = self._prevent_method_masking)
|
||||
l.append(n)
|
||||
v = l
|
||||
self._map[k] = v
|
||||
if kwargs:
|
||||
for k,v in self.__call_items(kwargs):
|
||||
if self._prevent_method_masking and k in reserved_keys:
|
||||
raise KeyError('"{}" is reserved'.format(k))
|
||||
if _key_convert_hook:
|
||||
k = _key_convert_hook(k)
|
||||
self._map[k] = v
|
||||
|
||||
def __call_items(self, obj):
|
||||
if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
|
||||
return obj.iteritems()
|
||||
else:
|
||||
return obj.items()
|
||||
|
||||
def items(self):
|
||||
return self.iteritems()
|
||||
|
||||
def iteritems(self):
|
||||
return self.__call_items(self._map)
|
||||
|
||||
def __iter__(self):
|
||||
return self._map.__iter__()
|
||||
|
||||
def next(self):
|
||||
return self._map.next()
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
self._map[k] = v
|
||||
def __getitem__(self, k):
|
||||
if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_':
|
||||
# automatically extend to new DotMap
|
||||
self[k] = self.__class__()
|
||||
return self._map[k]
|
||||
|
||||
def __setattr__(self, k, v):
|
||||
if k in {'_map','_dynamic', '_ipython_canary_method_should_not_exist_', '_prevent_method_masking'}:
|
||||
super(DotMap, self).__setattr__(k,v)
|
||||
elif self._prevent_method_masking and k in reserved_keys:
|
||||
raise KeyError('"{}" is reserved'.format(k))
|
||||
else:
|
||||
self[k] = v
|
||||
|
||||
def __getattr__(self, k):
|
||||
if k.startswith('__') and k.endswith('__'):
|
||||
raise AttributeError(k)
|
||||
|
||||
if k in {'_map','_dynamic','_ipython_canary_method_should_not_exist_'}:
|
||||
return super(DotMap, self).__getattr__(k)
|
||||
|
||||
try:
|
||||
v = super(self.__class__, self).__getattribute__(k)
|
||||
return v
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return self[k]
|
||||
except KeyError:
|
||||
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{k}'") from None
|
||||
|
||||
def __delattr__(self, key):
|
||||
return self._map.__delitem__(key)
|
||||
|
||||
def __contains__(self, k):
|
||||
return self._map.__contains__(k)
|
||||
|
||||
def __add__(self, other):
|
||||
if self.empty():
|
||||
return other
|
||||
else:
|
||||
self_type = type(self).__name__
|
||||
other_type = type(other).__name__
|
||||
msg = "unsupported operand type(s) for +: '{}' and '{}'"
|
||||
raise TypeError(msg.format(self_type, other_type))
|
||||
|
||||
def __str__(self, seen = None):
|
||||
items = []
|
||||
seen = {id(self)} if seen is None else seen
|
||||
for k,v in self.__call_items(self._map):
|
||||
# circular assignment case
|
||||
if isinstance(v, self.__class__):
|
||||
if id(v) in seen:
|
||||
items.append('{0}={1}(...)'.format(k, self.__class__.__name__))
|
||||
else:
|
||||
seen.add(id(v))
|
||||
items.append('{0}={1}'.format(k, v.__str__(seen)))
|
||||
else:
|
||||
items.append('{0}={1}'.format(k, repr(v)))
|
||||
joined = ', '.join(items)
|
||||
out = '{0}({1})'.format(self.__class__.__name__, joined)
|
||||
return out
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
def toDict(self, seen = None):
|
||||
if seen is None:
|
||||
seen = {}
|
||||
|
||||
d = {}
|
||||
|
||||
seen[id(self)] = d
|
||||
|
||||
for k,v in self.items():
|
||||
if issubclass(type(v), DotMap):
|
||||
idv = id(v)
|
||||
if idv in seen:
|
||||
v = seen[idv]
|
||||
else:
|
||||
v = v.toDict(seen = seen)
|
||||
elif type(v) in (list, tuple):
|
||||
l = []
|
||||
for i in v:
|
||||
n = i
|
||||
if issubclass(type(i), DotMap):
|
||||
idv = id(n)
|
||||
if idv in seen:
|
||||
n = seen[idv]
|
||||
else:
|
||||
n = i.toDict(seen = seen)
|
||||
l.append(n)
|
||||
if type(v) is tuple:
|
||||
v = tuple(l)
|
||||
else:
|
||||
v = l
|
||||
d[k] = v
|
||||
return d
|
||||
|
||||
def pprint(self, pformat='dict'):
|
||||
if pformat == 'json':
|
||||
print(dumps(self.toDict(), indent=4, sort_keys=True))
|
||||
else:
|
||||
pprint(self.toDict())
|
||||
|
||||
def empty(self):
|
||||
return (not any(self))
|
||||
|
||||
# proper dict subclassing
|
||||
def values(self):
|
||||
return self._map.values()
|
||||
|
||||
# ipython support
|
||||
def __dir__(self):
|
||||
return self.keys()
|
||||
|
||||
@classmethod
|
||||
def parseOther(self, other):
|
||||
if issubclass(type(other), DotMap):
|
||||
return other._map
|
||||
else:
|
||||
return other
|
||||
def __cmp__(self, other):
|
||||
other = DotMap.parseOther(other)
|
||||
return self._map.__cmp__(other)
|
||||
def __eq__(self, other):
|
||||
other = DotMap.parseOther(other)
|
||||
if not isinstance(other, dict):
|
||||
return False
|
||||
return self._map.__eq__(other)
|
||||
def __ge__(self, other):
|
||||
other = DotMap.parseOther(other)
|
||||
return self._map.__ge__(other)
|
||||
def __gt__(self, other):
|
||||
other = DotMap.parseOther(other)
|
||||
return self._map.__gt__(other)
|
||||
def __le__(self, other):
|
||||
other = DotMap.parseOther(other)
|
||||
return self._map.__le__(other)
|
||||
def __lt__(self, other):
|
||||
other = DotMap.parseOther(other)
|
||||
return self._map.__lt__(other)
|
||||
def __ne__(self, other):
|
||||
other = DotMap.parseOther(other)
|
||||
return self._map.__ne__(other)
|
||||
|
||||
def __delitem__(self, key):
|
||||
return self._map.__delitem__(key)
|
||||
def __len__(self):
|
||||
return self._map.__len__()
|
||||
def clear(self):
|
||||
self._map.clear()
|
||||
def copy(self):
|
||||
return self.__class__(self)
|
||||
def __copy__(self):
|
||||
return self.copy()
|
||||
def __deepcopy__(self, memo=None):
|
||||
return self.copy()
|
||||
def get(self, key, default=None):
|
||||
return self._map.get(key, default)
|
||||
def has_key(self, key):
|
||||
return key in self._map
|
||||
def iterkeys(self):
|
||||
return self._map.iterkeys()
|
||||
def itervalues(self):
|
||||
return self._map.itervalues()
|
||||
def keys(self):
|
||||
return self._map.keys()
|
||||
def pop(self, key, default=None):
|
||||
return self._map.pop(key, default)
|
||||
def popitem(self):
|
||||
return self._map.popitem()
|
||||
def setdefault(self, key, default=None):
|
||||
return self._map.setdefault(key, default)
|
||||
def update(self, *args, **kwargs):
|
||||
if len(args) != 0:
|
||||
self._map.update(*args)
|
||||
self._map.update(kwargs)
|
||||
def viewitems(self):
|
||||
return self._map.viewitems()
|
||||
def viewkeys(self):
|
||||
return self._map.viewkeys()
|
||||
def viewvalues(self):
|
||||
return self._map.viewvalues()
|
||||
@classmethod
|
||||
def fromkeys(cls, seq, value=None):
|
||||
d = cls()
|
||||
d._map = OrderedDict.fromkeys(seq, value)
|
||||
return d
|
||||
def __getstate__(self): return self.__dict__
|
||||
def __setstate__(self, d): self.__dict__.update(d)
|
||||
# bannerStr
|
||||
def _getListStr(self,items):
|
||||
out = '['
|
||||
mid = ''
|
||||
for i in items:
|
||||
mid += ' {}\n'.format(i)
|
||||
if mid != '':
|
||||
mid = '\n' + mid
|
||||
out += mid
|
||||
out += ']'
|
||||
return out
|
||||
def _getValueStr(self,k,v):
|
||||
outV = v
|
||||
multiLine = len(str(v).split('\n')) > 1
|
||||
if multiLine:
|
||||
# push to next line
|
||||
outV = '\n' + v
|
||||
if type(v) is list:
|
||||
outV = self._getListStr(v)
|
||||
out = '{} {}'.format(k,outV)
|
||||
return out
|
||||
def _getSubMapDotList(self, pre, name, subMap):
|
||||
outList = []
|
||||
if pre == '':
|
||||
pre = name
|
||||
else:
|
||||
pre = '{}.{}'.format(pre,name)
|
||||
def stamp(pre,k,v):
|
||||
valStr = self._getValueStr(k,v)
|
||||
return '{}.{}'.format(pre, valStr)
|
||||
for k,v in subMap.items():
|
||||
if isinstance(v,DotMap) and v != DotMap():
|
||||
subList = self._getSubMapDotList(pre,k,v)
|
||||
outList.extend(subList)
|
||||
else:
|
||||
outList.append(stamp(pre,k,v))
|
||||
return outList
|
||||
def _getSubMapStr(self, name, subMap):
|
||||
outList = ['== {} =='.format(name)]
|
||||
for k,v in subMap.items():
|
||||
if isinstance(v, self.__class__) and v != self.__class__():
|
||||
# break down to dots
|
||||
subList = self._getSubMapDotList('',k,v)
|
||||
# add the divit
|
||||
# subList = ['> {}'.format(i) for i in subList]
|
||||
outList.extend(subList)
|
||||
else:
|
||||
out = self._getValueStr(k,v)
|
||||
# out = '> {}'.format(out)
|
||||
out = '{}'.format(out)
|
||||
outList.append(out)
|
||||
finalOut = '\n'.join(outList)
|
||||
return finalOut
|
||||
def bannerStr(self):
|
||||
lines = []
|
||||
previous = None
|
||||
for k,v in self.items():
|
||||
if previous == self.__class__.__name__:
|
||||
lines.append('-')
|
||||
out = ''
|
||||
if isinstance(v, self.__class__):
|
||||
name = k
|
||||
subMap = v
|
||||
out = self._getSubMapStr(name,subMap)
|
||||
lines.append(out)
|
||||
previous = self.__class__.__name__
|
||||
else:
|
||||
out = self._getValueStr(k,v)
|
||||
lines.append(out)
|
||||
previous = 'other'
|
||||
lines.append('--')
|
||||
s = '\n'.join(lines)
|
||||
return s
|
||||
|
||||
reserved_keys = {i for i in dir(DotMap) if not i.startswith('__') and not i.endswith('__')}
|
||||
|
@ -310,27 +310,6 @@ def makehtml(text,base=False,show=None):
|
||||
show=text
|
||||
return '<a href="{}">{}</a>'.format(text,show)
|
||||
|
||||
def loadfridascriptslist(path,Scriptscombo):
|
||||
Scriptscombo.clear()
|
||||
try:
|
||||
def check(f):
|
||||
if f.endswith('.js')==False:return False
|
||||
if f.startswith('lib'):return False
|
||||
return True
|
||||
fridascripts =[]
|
||||
for f in os.listdir(os.path.join(path,'scripts')):
|
||||
|
||||
if os.path.isdir(os.path.join(path,'scripts',f)):
|
||||
for ff in os.listdir(os.path.join(path,'scripts',f)):
|
||||
if check(ff):
|
||||
fridascripts.append(f+'/'+ff[:-3])
|
||||
else:
|
||||
if check(f):
|
||||
fridascripts.append(f[:-3])
|
||||
except:
|
||||
fridascripts=[]
|
||||
Scriptscombo.addItems(fridascripts)
|
||||
return fridascripts
|
||||
import sqlite3
|
||||
class autosql(sqlite3.Connection):
|
||||
def __new__(cls,v) -> None:
|
||||
|
@ -1,185 +0,0 @@
|
||||
|
||||
import queue
|
||||
from textsource.textsourcebase import basetext
|
||||
from myutils.config import globalconfig,savehook_new_data
|
||||
from gobject import gprint
|
||||
import gobject
|
||||
import os,sys,platform
|
||||
from myutils.utils import stringfyerror
|
||||
from traceback import print_exc
|
||||
from myutils.dotmap import DotMap
|
||||
|
||||
def buildfridaclass(copycallback,pexe):
|
||||
try:
|
||||
import frida
|
||||
except ModuleNotFoundError:
|
||||
if platform.architecture()[0]=='64bit':
|
||||
pythonbit='64'
|
||||
else:
|
||||
pythonbit='86'
|
||||
sys.path.append(os.path.join(globalconfig['fridahook']['path'],'runtime/x'+pythonbit))
|
||||
import frida
|
||||
class Frida:
|
||||
def __init__(self) -> None:
|
||||
self.session=None
|
||||
def eval_func_statPath(self,args):
|
||||
e,t=args
|
||||
e = os.path.join(t, e)
|
||||
i = {
|
||||
'path': e ,
|
||||
'isFile': False,
|
||||
'isDir': False
|
||||
}
|
||||
try:
|
||||
i['isFile']=os.path.isfile(e)
|
||||
i['isDir']=os.path.isdir(e)
|
||||
except:
|
||||
i['errno']=True
|
||||
return i
|
||||
def eval_fs_readFileSync(self,args):
|
||||
e,t=args
|
||||
try:
|
||||
with open(e,'r',encoding=t) as ff:
|
||||
return ff.read()
|
||||
except:
|
||||
return None
|
||||
def eval_path_dirname(self,args):
|
||||
return os.path.dirname(args[0])
|
||||
def eval_fs_writeFileSync(self,args):
|
||||
if len(args)==2:
|
||||
e,t=args
|
||||
i='w'
|
||||
else:
|
||||
raise Exception(args)
|
||||
with open(e,i) as ff:
|
||||
ff.write(t)
|
||||
def log_handler(self,e,t):
|
||||
gprint(e,t)
|
||||
pass
|
||||
def cmd_copy(self,payload):
|
||||
gprint(payload.text )
|
||||
def cmd_default(self,payload):
|
||||
self.script.post({ 'type': payload.key })
|
||||
def cmd_rpc_send(self,payload):
|
||||
i = payload.func,
|
||||
gprint(i)
|
||||
def cmd_rpc_invoke(self,payload):
|
||||
i = payload.func,
|
||||
gprint(i)
|
||||
def cmd_eval(self,payload):
|
||||
funcs={
|
||||
'__dirname':lambda _:self.scriptdir,
|
||||
'__mission':lambda _:self.scriptjsfn,
|
||||
'_statPath':self.eval_func_statPath,
|
||||
'fs_realpathSync':lambda _:os.path.abspath(_[0]),
|
||||
'fs_readFileSync':self.eval_fs_readFileSync,
|
||||
'path_dirname':lambda _:os.path.dirname(_[0]),
|
||||
'fs_writeFileSync':self.eval_fs_writeFileSync
|
||||
}
|
||||
func=funcs.get(payload.func)
|
||||
s=func(payload.args)
|
||||
if type(s)==bytes:
|
||||
self.script.post({'type':payload.key},s)
|
||||
else:
|
||||
self.script.post({'type':payload.key,'result':s})
|
||||
def cmd_prompt(self,payload):
|
||||
t=payload.text
|
||||
r=payload.default
|
||||
if not r:
|
||||
r=''
|
||||
try:
|
||||
r= savehook_new_data[pexe]['fridahook']['prompt'][t]
|
||||
except:
|
||||
pass
|
||||
def callback(texts):
|
||||
text=texts[0]
|
||||
self.script.post({'type':payload.key,'result':text})
|
||||
try:
|
||||
savehook_new_data[pexe]['fridahook']['prompt'].update({t:text})
|
||||
except:
|
||||
savehook_new_data[pexe]['fridahook'].update({'prompt':{t:text}})
|
||||
gobject.baseobject.Prompt.call.emit('prompt',t,[r],[callback])
|
||||
|
||||
|
||||
def on_message(self,raw_message: str, data):
|
||||
e=DotMap(raw_message)
|
||||
gprint(raw_message)
|
||||
|
||||
if "error" == e.type:
|
||||
gprint('error',e)
|
||||
if e.description:
|
||||
gobject.baseobject.textgetmethod('<msg_error_not_refresh>'+str(e.description))
|
||||
return
|
||||
if 0 == e.payload:
|
||||
gprint('error',e)
|
||||
return
|
||||
payloadfunctions={
|
||||
'copy':copycallback,
|
||||
'rpc_invoke':self.cmd_rpc_invoke,
|
||||
'rpc_send':self.cmd_rpc_send,
|
||||
'eval':self.cmd_eval,
|
||||
'prompt':self.cmd_prompt
|
||||
}
|
||||
default=self.cmd_default
|
||||
func=payloadfunctions.get(e.payload.cmd,default)
|
||||
func(e.payload)
|
||||
def on_destroyed(self):
|
||||
pass
|
||||
def attach(self,target,scriptjsfn):
|
||||
session=frida.attach(target)
|
||||
self.session=session
|
||||
loader=os.path.abspath(os.path.join(globalconfig['fridahook']['path'], "scripts/libLoader.js"));
|
||||
self.scriptdir=os.path.dirname(loader)
|
||||
self.scriptjsfn=os.path.abspath(os.path.join(globalconfig['fridahook']['path'],"scripts/"+scriptjsfn));
|
||||
with open(loader,'r',encoding='utf8') as ff:
|
||||
code = ff.read()
|
||||
script =session.create_script(code);
|
||||
self.script=script
|
||||
script.set_log_handler(self.log_handler)
|
||||
script.on('message',self.on_message)
|
||||
script.on('destroyed',self.on_destroyed)
|
||||
script.load()
|
||||
|
||||
def run(self,exe,scriptjsfn):
|
||||
pid=frida.spawn(exe)
|
||||
self.attach(pid,scriptjsfn)
|
||||
frida.resume(pid)
|
||||
return pid
|
||||
def detach(self):
|
||||
if self.session:
|
||||
self.script.unload()
|
||||
self.session.detach()
|
||||
return Frida
|
||||
class fridahook(basetext):
|
||||
def override_cmd_copy(self,payload):
|
||||
self.getnewdata.put(payload.text)
|
||||
def __init__(self,_type,script,pname,pid=0,hwnd=0) -> None:
|
||||
self.getnewdata=queue.Queue()
|
||||
self.hwnd=hwnd
|
||||
|
||||
savehook_new_data[pname]['fridahook'].update({
|
||||
'js':script,
|
||||
'loadmethod':_type
|
||||
})
|
||||
|
||||
self.pname=pname
|
||||
try:
|
||||
self.showgamename()
|
||||
self.frida=buildfridaclass(self.override_cmd_copy,pname)()
|
||||
if _type==1:
|
||||
pid=self.frida.run(pname,f"{script}.js")
|
||||
elif _type==0:
|
||||
self.frida.attach(pid,f"{script}.js")
|
||||
self.pids=[pid]
|
||||
except Exception as e:
|
||||
self.pids=[]
|
||||
gobject.baseobject.textgetmethod('<msg_error_refresh>'+stringfyerror(e))
|
||||
print_exc()
|
||||
super(fridahook,self).__init__(*self.checkmd5prefix(pname))
|
||||
def end(self):
|
||||
self.frida.detach()
|
||||
def gettextthread(self ):
|
||||
self.runonce_line=self.getnewdata.get().replace('\x00','')
|
||||
return self.runonce_line
|
||||
def gettextonce(self):
|
||||
return self.runonce_line
|
@ -698,17 +698,10 @@
|
||||
},
|
||||
"texthook": {
|
||||
"use": true
|
||||
},
|
||||
"fridahook":{
|
||||
"use": false
|
||||
}
|
||||
},
|
||||
"verticalocr": false,
|
||||
"ocrmergelines": true,
|
||||
"fridahook":{
|
||||
"path":"",
|
||||
"autoupdate":true
|
||||
},
|
||||
"ocr": {
|
||||
"local": {
|
||||
"use": true,
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
add_library(hookmagpie MODULE hookmagpie.cpp)
|
||||
target_link_libraries(hookmagpie minhook ${Detours})
|
||||
add_library(hookmagpie MODULE hookmagpie.cpp veh_hook.cpp)
|
||||
target_link_libraries(hookmagpie ${Detours})
|
||||
endif()
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include<detours.h>
|
||||
#include<string>
|
||||
#include<assert.h>
|
||||
#include<MinHook.h>
|
||||
#include"veh_hook.h"
|
||||
namespace Win32Utils{
|
||||
static HANDLE SafeHandle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
struct HandleCloser { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) CloseHandle(h); } };
|
||||
@ -126,88 +126,14 @@ bool checkislunawindow(HWND hwndSrc)
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
class hooks{
|
||||
public:
|
||||
void IsValidSrcWindow_hooked(uintptr_t lpDataBase)
|
||||
{
|
||||
auto stack=(hook_stack*)(lpDataBase-sizeof(hook_stack)+sizeof(uintptr_t));
|
||||
auto hwndSrc=(HWND)(stack->rcx);
|
||||
void hookedisvalidwindow(PCONTEXT context){
|
||||
auto hwndSrc=(HWND)(context->Rcx);
|
||||
if (checkislunawindow(hwndSrc))
|
||||
{
|
||||
//MessageBoxW(0,GetExeName(hwndSrc).c_str(),L"",0);
|
||||
stack->rcx=(uintptr_t)FindWindow(L"Shell_TrayWnd",nullptr);
|
||||
context->Rcx=(uintptr_t)FindWindow(L"Shell_TrayWnd",nullptr);
|
||||
}
|
||||
}
|
||||
hooks(LPVOID location){
|
||||
BYTE common_hook[] = {
|
||||
0x9c, // push rflags
|
||||
0x50, // push rax
|
||||
0x53, // push rbx
|
||||
0x51, // push rcx
|
||||
0x52, // push rdx
|
||||
0x54, // push rsp
|
||||
0x55, // push rbp
|
||||
0x56, // push rsi
|
||||
0x57, // push rdi
|
||||
0x41, 0x50, // push r8
|
||||
0x41, 0x51, // push r9
|
||||
0x41, 0x52, // push r10
|
||||
0x41, 0x53, // push r11
|
||||
0x41, 0x54, // push r12
|
||||
0x41, 0x55, // push r13
|
||||
0x41, 0x56, // push r14
|
||||
0x41, 0x57, // push r15
|
||||
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
|
||||
// https://stackoverflow.com/questions/43358429/save-value-of-xmm-registers
|
||||
0x48, 0x83, 0xec, 0x20, // sub rsp,0x20
|
||||
0xf3, 0x0f, 0x7f, 0x24, 0x24, // movdqu [rsp],xmm4
|
||||
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x10, // movdqu [rsp+0x10],xmm5
|
||||
0x48, 0x8d, 0x94, 0x24, 0xa8, 0x00, 0x00, 0x00, // lea rdx,[rsp+0xa8]
|
||||
0x48, 0xb9, 0,0,0,0,0,0,0,0, // mov rcx,@this
|
||||
0x48, 0xb8, 0,0,0,0,0,0,0,0, // mov rax,@TextHook::Send
|
||||
0x48, 0x89, 0xe3, // mov rbx,rsp
|
||||
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
|
||||
0xff, 0xd0, // call rax
|
||||
0x48, 0x89, 0xdc, // mov rsp,rbx
|
||||
0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x10, // movdqu xmm5,XMMWORD PTR[rsp + 0x10]
|
||||
0xf3, 0x0f, 0x6f, 0x24, 0x24, // movdqu xmm4,XMMWORD PTR[rsp]
|
||||
0x48, 0x83, 0xc4, 0x20, // add rsp,0x20
|
||||
0x41, 0x5f, // pop r15
|
||||
0x41, 0x5e, // pop r14
|
||||
0x41, 0x5d, // pop r13
|
||||
0x41, 0x5c, // pop r12
|
||||
0x41, 0x5b, // pop r11
|
||||
0x41, 0x5a, // pop r10
|
||||
0x41, 0x59, // pop r9
|
||||
0x41, 0x58, // pop r8
|
||||
0x5f, // pop rdi
|
||||
0x5e, // pop rsi
|
||||
0x5d, // pop rbp
|
||||
0x5c, // pop rsp
|
||||
0x5a, // pop rdx
|
||||
0x59, // pop rcx
|
||||
0x5b, // pop rbx
|
||||
0x58, // pop rax
|
||||
0x9d, // pop rflags
|
||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip]
|
||||
0,0,0,0,0,0,0,0 // @original
|
||||
};
|
||||
int this_offset = 50, send_offset = 60, original_offset = 126;
|
||||
DWORD _;
|
||||
VirtualProtect(location, 10, PAGE_EXECUTE_READWRITE, &_);
|
||||
auto trampoline=VirtualAlloc(0,sizeof(common_hook),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
|
||||
void* original;
|
||||
MH_STATUS error;
|
||||
if ((error = MH_CreateHook(location, trampoline, &original)) != MH_OK)
|
||||
return;
|
||||
|
||||
*(hooks**)(common_hook + this_offset) = this;
|
||||
*(void(hooks::**)(uintptr_t))(common_hook + send_offset) = &hooks::IsValidSrcWindow_hooked;
|
||||
*(void**)(common_hook + original_offset) = original;
|
||||
memcpy(trampoline, common_hook, sizeof(common_hook));
|
||||
MH_EnableHook(location);
|
||||
}
|
||||
};
|
||||
void starthookmagpie()
|
||||
{
|
||||
uintptr_t IsValidSrcWindow=0;
|
||||
@ -239,8 +165,7 @@ void starthookmagpie()
|
||||
if(IsValidSrcWindow==0)return;
|
||||
|
||||
//IsValidSrcWindow=(decltype(IsValidSrcWindow))((uintptr_t)GetModuleHandle(L"Magpie.App.dll")+0x180146860-0x180000000);
|
||||
MH_Initialize();
|
||||
hooks _((LPVOID)IsValidSrcWindow);
|
||||
add_veh_hook((LPVOID)IsValidSrcWindow,hookedisvalidwindow,0);
|
||||
// DetourTransactionBegin();
|
||||
// DetourUpdateThread(GetCurrentThread());
|
||||
// DetourAttach(&(PVOID&)IsValidSrcWindow,IsValidSrcWindow_hooked);
|
||||
|
171
plugins/hookmagpie/veh_hook.cpp
Normal file
171
plugins/hookmagpie/veh_hook.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
/**
|
||||
veh_hook Vectored Exception Handler hooking library
|
||||
Version: 24-March-2008
|
||||
**/
|
||||
// #define WINVER 0x0501
|
||||
// #define _WIN32_WINNT 0x0501
|
||||
#include <windows.h>
|
||||
#include "veh_hook.h"
|
||||
#include<mutex>
|
||||
static veh_list_t* list = NULL;
|
||||
char int3bp[] = "\xCC";
|
||||
std::mutex vehlistlock;
|
||||
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type)
|
||||
{
|
||||
std::lock_guard _(vehlistlock);
|
||||
//static veh_list_t* list = NULL;
|
||||
DWORD oldProtect;
|
||||
if (list == NULL) list = new_veh_list();
|
||||
if (list == NULL) return false;
|
||||
void* handle = AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)veh_dispatch);
|
||||
veh_node_t* newnode = insert_veh_node(list, origFunc, newFunc, handle, hook_type);
|
||||
|
||||
// For memory hooks especially, we need to know the address of the start of the relevant page.
|
||||
MEMORY_BASIC_INFORMATION mem_info;
|
||||
VirtualQuery(origFunc, &mem_info, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
newnode->baseAddr = mem_info.BaseAddress;
|
||||
|
||||
VirtualProtect(origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &newnode->OldProtect);
|
||||
memcpy((void*)(&newnode->origBaseByte), (const void*)origFunc, sizeof (BYTE));
|
||||
memcpy((void*)origFunc, (const void*)&int3bp, sizeof (BYTE));
|
||||
VirtualProtect(origFunc, sizeof(int), newnode->OldProtect, &oldProtect);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remove_veh_hook(void* origFunc)
|
||||
{
|
||||
std::lock_guard _(vehlistlock);
|
||||
if (list == NULL) return false;
|
||||
veh_node_t* node = get_veh_node(list, origFunc);
|
||||
if (node == NULL) return false;
|
||||
DWORD _p;
|
||||
VirtualProtect(node->origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &_p);
|
||||
memcpy((void*)node->origFunc, (const void*)(&node->origBaseByte), sizeof(char));
|
||||
VirtualProtect(node->origFunc, sizeof(int), node->OldProtect, &_p);
|
||||
RemoveVectoredExceptionHandler(node->handle);
|
||||
return remove_veh_node(list, origFunc);
|
||||
}
|
||||
|
||||
bool remove_veh_node(veh_list_t* list, void* origFunc)
|
||||
{
|
||||
veh_node_t* searchnode;
|
||||
veh_node_t* lastsearchnode = NULL;
|
||||
searchnode = list->head;
|
||||
|
||||
while (searchnode != NULL)
|
||||
{
|
||||
if (searchnode->origFunc == origFunc)
|
||||
{
|
||||
if (lastsearchnode == NULL)
|
||||
{
|
||||
list->head = searchnode->next;
|
||||
if (list->tail == searchnode) list->tail = searchnode->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastsearchnode->next = searchnode->next;
|
||||
}
|
||||
delete (searchnode);
|
||||
return true;
|
||||
}
|
||||
lastsearchnode = searchnode;
|
||||
searchnode = searchnode->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
|
||||
{
|
||||
|
||||
DWORD oldProtect;
|
||||
void* Addr = ExceptionInfo->ExceptionRecord->ExceptionAddress;
|
||||
ULONG Code = ExceptionInfo->ExceptionRecord->ExceptionCode;
|
||||
|
||||
if (Code != STATUS_BREAKPOINT && Code != STATUS_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH;
|
||||
// Try to find the node associated with the address of the current exception, continue searching for handlers if not found;
|
||||
std::lock_guard _(vehlistlock);
|
||||
if (Code == STATUS_BREAKPOINT )//&& hooktype == VEH_HK_INT3)
|
||||
{
|
||||
veh_node_t* currnode = get_veh_node(list, Addr);
|
||||
if (currnode == NULL) return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect);
|
||||
memcpy((void*)Addr, (const void*)(&currnode->origBaseByte), sizeof (char));
|
||||
currnode->newFunc(ExceptionInfo->ContextRecord);
|
||||
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect);
|
||||
ExceptionInfo->ContextRecord->EFlags |= 0x100;
|
||||
|
||||
}
|
||||
else if (Code == STATUS_SINGLE_STEP )//&& hooktype == VEH_HK_INT3)
|
||||
{
|
||||
veh_node_t* currnode = get_veh_node(list, Addr, 0x10);
|
||||
if (currnode == NULL) return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect);
|
||||
memcpy((void*)currnode->origFunc, (const void*)&int3bp, sizeof (BYTE));
|
||||
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect);
|
||||
ExceptionInfo->ContextRecord->EFlags &= ~0x00000100; // Remove TRACE from EFLAGS
|
||||
|
||||
}
|
||||
// else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_HW)
|
||||
// {
|
||||
// currnode->newFunc(ExceptionInfo->ContextRecord);
|
||||
// }
|
||||
// else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_MEM)
|
||||
// {
|
||||
|
||||
// currnode->newFunc(ExceptionInfo->ContextRecord);
|
||||
// }
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
veh_list_t* new_veh_list()
|
||||
{
|
||||
veh_list_t* newlist = (veh_list_t*)malloc(sizeof(veh_list_t));
|
||||
if (newlist == NULL) return NULL;
|
||||
newlist->head = NULL;
|
||||
newlist->tail = NULL;
|
||||
return newlist;
|
||||
}
|
||||
veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type)
|
||||
{
|
||||
if (list == NULL) return NULL;
|
||||
/* create a new node and fill in the blanks */
|
||||
veh_node_t* newnode = new veh_node_t;
|
||||
if (newnode == NULL) return NULL;
|
||||
newnode->origFunc = origFunc;
|
||||
newnode->newFunc = newFunc;
|
||||
newnode->handle = handle;
|
||||
newnode->OldProtect = PAGE_EXECUTE_READWRITE;
|
||||
newnode->next = NULL;
|
||||
newnode->hooktype=hook_type;
|
||||
if (list->head == NULL)
|
||||
{
|
||||
list->head = newnode;
|
||||
list->tail = newnode;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->tail->next = newnode;
|
||||
list->tail = newnode;
|
||||
}
|
||||
return newnode;
|
||||
}
|
||||
|
||||
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, int range)
|
||||
{
|
||||
veh_node_t* newnode;
|
||||
veh_node_t* closestnode = NULL;
|
||||
if (list == NULL) return NULL;
|
||||
newnode = list->head;
|
||||
while (newnode != NULL)
|
||||
{
|
||||
if(((uintptr_t)origFunc-(uintptr_t)newnode->origFunc)<=range)
|
||||
{
|
||||
closestnode=newnode;
|
||||
if(range==0)break;
|
||||
range=((uintptr_t)origFunc-(uintptr_t)newnode->origFunc);
|
||||
}
|
||||
newnode = newnode->next;
|
||||
}
|
||||
return closestnode;
|
||||
}
|
57
plugins/hookmagpie/veh_hook.h
Normal file
57
plugins/hookmagpie/veh_hook.h
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
veh_hook Vectored Exception Handler hooking library
|
||||
Version: 24-March-2008
|
||||
**/
|
||||
|
||||
#ifndef LIST_T_H_INCLUDED
|
||||
#define LIST_T_H_INCLUDED
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include<functional>
|
||||
// VEH Hooking types
|
||||
#define VEH_HK_INT3 0
|
||||
#define VEH_HK_MEM 1
|
||||
#define VEH_HK_HW 2
|
||||
// -
|
||||
|
||||
#define OPCODE_INT3 "\xCC"
|
||||
|
||||
|
||||
//typedef void (*pfvoid)();
|
||||
//typedef void (*newFuncType)(PCONTEXT);
|
||||
using newFuncType = void(*)(PCONTEXT);//std::function<void(PCONTEXT)>;
|
||||
|
||||
typedef struct veh_node
|
||||
{
|
||||
void* origFunc;
|
||||
newFuncType newFunc;
|
||||
void* handle;
|
||||
DWORD hooktype;
|
||||
void* baseAddr; // Address of the page in which origFunc resides.
|
||||
BYTE origBaseByte;
|
||||
DWORD OldProtect;
|
||||
struct veh_node* next;
|
||||
} veh_node_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
veh_node_t* head;
|
||||
veh_node_t* tail;
|
||||
} veh_list_t;
|
||||
|
||||
// VEH hook interface functions for creating and removing hooks.
|
||||
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type);
|
||||
bool remove_veh_hook(void* origFunc);
|
||||
|
||||
// The VEH dispathing function is called by Windows every time an exception is encountered.
|
||||
// the function dispatches calls to the correct inctercept function.
|
||||
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo);
|
||||
|
||||
// Functions used internally by the library.
|
||||
veh_list_t* new_veh_list();
|
||||
veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type);
|
||||
bool remove_veh_node(veh_list_t* list, void* origFunc);
|
||||
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, int range=0);
|
||||
|
||||
#endif // LIST_T_H_INCLUDED
|
@ -7,7 +7,6 @@ endif()
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/Detours-4.0.1/include)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/minhook)
|
||||
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4)
|
||||
set(LTLPlatform "Win32")
|
||||
|
@ -1,22 +0,0 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Windows-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = crlf
|
||||
insert_final_newline = true
|
||||
|
||||
# 4 space indentation
|
||||
[*.{c,h,def}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# Trim trailing whitespaces
|
||||
[*.{c,h,def,txt}]
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# UTF-8 with BOM
|
||||
[*.{c,h,def,txt}]
|
||||
charset=utf-8-bom
|
44
plugins/libs/minhook/.gitignore
vendored
44
plugins/libs/minhook/.gitignore
vendored
@ -1,44 +0,0 @@
|
||||
#OS junk files
|
||||
[Tt]humbs.db
|
||||
*.DS_Store
|
||||
|
||||
#Visual Studio files
|
||||
*.[Oo]bj
|
||||
*.user
|
||||
*.aps
|
||||
*.pch
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ncb
|
||||
*.suo
|
||||
*.tlb
|
||||
*.tlh
|
||||
*.bak
|
||||
*.[Cc]ache
|
||||
*.ilk
|
||||
*.log
|
||||
*.sbr
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.unsuccessfulbuild
|
||||
ipch/
|
||||
obj/
|
||||
[Ll]ib
|
||||
[Bb]in
|
||||
[Dd]ebug*/
|
||||
[Rr]elease*/
|
||||
Ankh.NoLoad
|
||||
*.VC.db
|
||||
.vs/
|
||||
|
||||
#GCC files
|
||||
*.o
|
||||
*.d
|
||||
*.res
|
||||
*.dll
|
||||
*.a
|
||||
|
||||
#Visual Studio Code files
|
||||
.vscode/
|
@ -1,8 +0,0 @@
|
||||
Tsuda Kageyu <tsuda.kageyu@gmail.com>
|
||||
Creator, maintainer
|
||||
|
||||
Michael Maltsev <leahcimmar@gmail.com>
|
||||
Added "Queue" functions. A lot of bug fixes.
|
||||
|
||||
Andrey Unis <uniskz@gmail.com>
|
||||
Rewrote the hook engine in plain C.
|
@ -1,141 +0,0 @@
|
||||
# MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
# Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(minhook LANGUAGES C)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
set(MINHOOK_MAJOR_VERSION 1)
|
||||
set(MINHOOK_MINOR_VERSION 3)
|
||||
set(MINHOOK_PATCH_VERSION 3)
|
||||
set(MINHOOK_VERSION ${MINHOOK_MAJOR_VERSION}.${MINHOOK_MINOR_VERSION}.${MINHOOK_PATCH_VERSION})
|
||||
|
||||
################
|
||||
# BUILD #
|
||||
################
|
||||
|
||||
option(BUILD_SHARED_LIBS "build shared version" OFF)
|
||||
|
||||
set(SOURCES_MINHOOK
|
||||
"src/buffer.c"
|
||||
"src/hook.c"
|
||||
"src/trampoline.c"
|
||||
)
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(SOURCES_HDE "src/hde/hde64.c")
|
||||
else()
|
||||
set(SOURCES_HDE "src/hde/hde32.c")
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(RESOURCES
|
||||
"dll_resources/minhook.rc"
|
||||
"dll_resources/minhook.def"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(minhook ${SOURCES_MINHOOK} ${SOURCES_HDE} ${RESOURCES})
|
||||
|
||||
target_include_directories(minhook PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
target_include_directories(minhook PRIVATE "src/")
|
||||
target_include_directories(minhook PRIVATE "src/hde/")
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(minhook PROPERTIES PREFIX "")
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set_target_properties(minhook PROPERTIES DEBUG_POSTFIX ".x64d")
|
||||
set_target_properties(minhook PROPERTIES RELEASE_POSTFIX ".x64")
|
||||
set_target_properties(minhook PROPERTIES RELWITHDEBINFO_POSTFIX ".x64")
|
||||
set_target_properties(minhook PROPERTIES MINSIZEREL_POSTFIX ".x64")
|
||||
else()
|
||||
set_target_properties(minhook PROPERTIES DEBUG_POSTFIX ".x32d")
|
||||
set_target_properties(minhook PROPERTIES RELEASE_POSTFIX ".x32")
|
||||
set_target_properties(minhook PROPERTIES RELWITHDEBINFO_POSTFIX ".x32")
|
||||
set_target_properties(minhook PROPERTIES MINSIZEREL_POSTFIX ".x64")
|
||||
endif()
|
||||
else()
|
||||
set_target_properties(minhook PROPERTIES PREFIX "lib")
|
||||
set_target_properties(minhook PROPERTIES POSTFIX "")
|
||||
set_target_properties(minhook PROPERTIES DEBUG_POSTFIX "d")
|
||||
endif()
|
||||
|
||||
################
|
||||
# CMAKE CONFIG #
|
||||
################
|
||||
|
||||
configure_package_config_file(
|
||||
"cmake/minhook-config.cmake.in"
|
||||
"minhook-config.cmake"
|
||||
INSTALL_DESTINATION
|
||||
"lib/minhook"
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"minhook-config-version.cmake"
|
||||
VERSION
|
||||
${MINHOOK_VERSION}
|
||||
COMPATIBILITY
|
||||
AnyNewerVersion
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/minhook-config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/minhook-config-version.cmake"
|
||||
DESTINATION
|
||||
"lib/minhook"
|
||||
)
|
||||
|
||||
###################
|
||||
# INSTALL #
|
||||
###################
|
||||
|
||||
install(TARGETS minhook
|
||||
EXPORT minhook-targets
|
||||
RUNTIME DESTINATION "bin"
|
||||
ARCHIVE DESTINATION "lib"
|
||||
LIBRARY DESTINATION "lib"
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT
|
||||
minhook-targets
|
||||
NAMESPACE
|
||||
minhook::
|
||||
DESTINATION
|
||||
"lib/minhook"
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY include DESTINATION .
|
||||
)
|
@ -1,81 +0,0 @@
|
||||
MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
================================================================================
|
||||
Hacker Disassembler Engine 32 C
|
||||
Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Hacker Disassembler Engine 64 C
|
||||
Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -1,87 +0,0 @@
|
||||
# MinHook
|
||||
|
||||
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
The Minimalistic x86/x64 API Hooking Library for Windows
|
||||
|
||||
http://www.codeproject.com/KB/winsdk/LibMinHook.aspx
|
||||
|
||||
### Version history
|
||||
|
||||
- **v1.3.3 - 8 Jan 2017**
|
||||
* Added a helper function ```MH_CreateHookApiEx```. (Thanks to asm256)
|
||||
* Support Visual Studio 2017 RC.
|
||||
|
||||
- **v1.3.2.1 - 9 Nov 2015** (Nuget package only)
|
||||
* Fixed an insufficient support for Visual Studio 2015.
|
||||
|
||||
- **v1.3.2 - 1 Nov 2015**
|
||||
* Support Visual Studio 2015.
|
||||
* Support MinGW.
|
||||
|
||||
- **v1.3.2-beta3 - 21 Jul 2015** (Nuget package only)
|
||||
* Support MinGW. (Experimental)
|
||||
|
||||
- **v1.3.2-beta2 - 18 May 2015**
|
||||
* Fixed some subtle bugs. (Thanks to RaMMicHaeL)
|
||||
* Added a helper function ```MH_StatusToString```. (Thanks to Jan Klass)
|
||||
|
||||
- **v1.3.2-beta - 12 May 2015**
|
||||
* Fixed a possible thread deadlock in x64 mode. (Thanks to Aleh Kazakevich)
|
||||
* Reduced the footprint a little more.
|
||||
* Support Visual Studio 2015 RC. (Experimental)
|
||||
|
||||
- **v1.3.1.1 - 7 Apr 2015** (Nuget package only)
|
||||
* Support for WDK8.0 and 8.1.
|
||||
|
||||
- **v1.3.1 - 19 Mar 2015**
|
||||
* No major changes from v1.3.1-beta.
|
||||
|
||||
- **v1.3.1-beta - 11 Mar 2015**
|
||||
* Added a helper function ```MH_CreateHookApi```. (Thanks to uniskz).
|
||||
* Fixed a false memory leak reported by some tools.
|
||||
* Fixed a degradated compatibility issue.
|
||||
|
||||
- **v1.3 - 13 Sep 2014**
|
||||
* No major changes from v1.3-beta3.
|
||||
|
||||
- **v1.3-beta3 - 31 Jul 2014**
|
||||
* Fixed some small bugs.
|
||||
* Improved the memory management.
|
||||
|
||||
- **v1.3-beta2 - 21 Jul 2014**
|
||||
* Changed the parameters to Windows-friendly types. (void* to LPVOID)
|
||||
* Fixed some small bugs.
|
||||
* Reorganized the source files.
|
||||
* Reduced the footprint a little more.
|
||||
|
||||
- **v1.3-beta - 17 Jul 2014**
|
||||
* Rewrote in plain C to reduce the footprint and memory usage. (suggested by Andrey Unis)
|
||||
* Simplified the overall code base to make it more readable and maintainable.
|
||||
* Changed the license from 3-clause to 2-clause BSD License.
|
||||
|
||||
- **v1.2 - 28 Sep 2013**
|
||||
* Removed boost dependency ([jarredholman](https://github.com/jarredholman/minhook)).
|
||||
* Fixed a small bug in the GetRelativeBranchDestination function ([pillbug99](http://www.codeproject.com/Messages/4058892/Small-Bug-Found.aspx)).
|
||||
* Added the ```MH_RemoveHook``` function, which removes a hook created with the ```MH_CreateHook``` function.
|
||||
* Added the following functions to enable or disable multiple hooks in one go: ```MH_QueueEnableHook```, ```MH_QueueDisableHook```, ```MH_ApplyQueued```. This is the preferred way of handling multiple hooks as every call to `MH_EnableHook` or `MH_DisableHook` suspends and resumes all threads.
|
||||
* Made the functions ```MH_EnableHook``` and ```MH_DisableHook``` enable/disable all created hooks when the ```MH_ALL_HOOKS``` parameter is passed. This, too, is an efficient way of handling multiple hooks.
|
||||
* If the target function is too small to be patched with a jump, MinHook tries to place the jump above the function. If that fails as well, the ```MH_CreateHook``` function returns ```MH_ERROR_UNSUPPORTED_FUNCTION```. This fixes an issue of hooking the LoadLibraryExW function on Windows 7 x64 ([reported by Obble](http://www.codeproject.com/Messages/4578613/Re-Bug-LoadLibraryExW-hook-fails-on-windows-2008-r.aspx)).
|
||||
|
||||
- **v1.1 - 26 Nov 2009**
|
||||
* Changed the interface to create a hook and a trampoline function in one go to prevent the detour function from being called before the trampoline function is created. ([reported by xliqz](http://www.codeproject.com/Messages/3280374/Unsafe.aspx))
|
||||
* Shortened the function names from ```MinHook_*``` to ```MH_*``` to make them handier.
|
||||
|
||||
- **v1.0 - 22 Nov 2009**
|
||||
* Initial release.
|
||||
|
||||
### Building MinHook - Using vcpkg
|
||||
|
||||
You can download and install MinHook using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
.\vcpkg\bootstrap-vcpkg.bat
|
||||
.\vcpkg\vcpkg integrate install
|
||||
.\vcpkg\vcpkg install minhook
|
||||
|
||||
The MinHook port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
@ -1,39 +0,0 @@
|
||||
# MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
# Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
set(MINHOOK_MAJOR_VERSION "@MINHOOK_MAJOR_VERSION@")
|
||||
set(MINHOOK_MINOR_VERSION "@MINHOOK_MINOR_VERSION@")
|
||||
set(MINHOOK_PATCH_VERSION "@MINHOOK_PATCH_VERSION@")
|
||||
set(MINHOOK_VERSION "@MINHOOK_VERSION@")
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set(MINHOOK_FOUND ON)
|
||||
|
||||
set_and_check(MINHOOK_INCLUDE_DIRS "${PACKAGE_PREFIX_DIR}/include/")
|
||||
set_and_check(MINHOOK_LIBRARY_DIRS "${PACKAGE_PREFIX_DIR}/lib")
|
||||
|
||||
include("${PACKAGE_PREFIX_DIR}/lib/minhook/minhook-targets.cmake")
|
@ -1,185 +0,0 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
|
||||
#error MinHook supports only x86 and x64 systems.
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// MinHook Error Codes.
|
||||
typedef enum MH_STATUS
|
||||
{
|
||||
// Unknown error. Should not be returned.
|
||||
MH_UNKNOWN = -1,
|
||||
|
||||
// Successful.
|
||||
MH_OK = 0,
|
||||
|
||||
// MinHook is already initialized.
|
||||
MH_ERROR_ALREADY_INITIALIZED,
|
||||
|
||||
// MinHook is not initialized yet, or already uninitialized.
|
||||
MH_ERROR_NOT_INITIALIZED,
|
||||
|
||||
// The hook for the specified target function is already created.
|
||||
MH_ERROR_ALREADY_CREATED,
|
||||
|
||||
// The hook for the specified target function is not created yet.
|
||||
MH_ERROR_NOT_CREATED,
|
||||
|
||||
// The hook for the specified target function is already enabled.
|
||||
MH_ERROR_ENABLED,
|
||||
|
||||
// The hook for the specified target function is not enabled yet, or already
|
||||
// disabled.
|
||||
MH_ERROR_DISABLED,
|
||||
|
||||
// The specified pointer is invalid. It points the address of non-allocated
|
||||
// and/or non-executable region.
|
||||
MH_ERROR_NOT_EXECUTABLE,
|
||||
|
||||
// The specified target function cannot be hooked.
|
||||
MH_ERROR_UNSUPPORTED_FUNCTION,
|
||||
|
||||
// Failed to allocate memory.
|
||||
MH_ERROR_MEMORY_ALLOC,
|
||||
|
||||
// Failed to change the memory protection.
|
||||
MH_ERROR_MEMORY_PROTECT,
|
||||
|
||||
// The specified module is not loaded.
|
||||
MH_ERROR_MODULE_NOT_FOUND,
|
||||
|
||||
// The specified function is not found.
|
||||
MH_ERROR_FUNCTION_NOT_FOUND
|
||||
}
|
||||
MH_STATUS;
|
||||
|
||||
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
|
||||
// MH_QueueEnableHook or MH_QueueDisableHook.
|
||||
#define MH_ALL_HOOKS NULL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Initialize the MinHook library. You must call this function EXACTLY ONCE
|
||||
// at the beginning of your program.
|
||||
MH_STATUS WINAPI MH_Initialize(VOID);
|
||||
|
||||
// Uninitialize the MinHook library. You must call this function EXACTLY
|
||||
// ONCE at the end of your program.
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID);
|
||||
|
||||
// Creates a hook for the specified target function, in disabled state.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszProcName [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszProcName [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
// ppTarget [out] A pointer to the target function, which will be used
|
||||
// with other functions.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
|
||||
|
||||
// Removes an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
|
||||
|
||||
// Enables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// enabled in one go.
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
|
||||
|
||||
// Disables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// disabled in one go.
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to enable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be enabled.
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to disable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be disabled.
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
|
||||
|
||||
// Applies all queued changes in one go.
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID);
|
||||
|
||||
// Translates the MH_STATUS to its name as a string.
|
||||
const char * WINAPI MH_StatusToString(MH_STATUS status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,312 +0,0 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "buffer.h"
|
||||
|
||||
// Size of each memory block. (= page size of VirtualAlloc)
|
||||
#define MEMORY_BLOCK_SIZE 0x1000
|
||||
|
||||
// Max range for seeking a memory block. (= 1024MB)
|
||||
#define MAX_MEMORY_RANGE 0x40000000
|
||||
|
||||
// Memory protection flags to check the executable address.
|
||||
#define PAGE_EXECUTE_FLAGS \
|
||||
(PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
|
||||
|
||||
// Memory slot.
|
||||
typedef struct _MEMORY_SLOT
|
||||
{
|
||||
union
|
||||
{
|
||||
struct _MEMORY_SLOT *pNext;
|
||||
UINT8 buffer[MEMORY_SLOT_SIZE];
|
||||
};
|
||||
} MEMORY_SLOT, *PMEMORY_SLOT;
|
||||
|
||||
// Memory block info. Placed at the head of each block.
|
||||
typedef struct _MEMORY_BLOCK
|
||||
{
|
||||
struct _MEMORY_BLOCK *pNext;
|
||||
PMEMORY_SLOT pFree; // First element of the free slot list.
|
||||
UINT usedCount;
|
||||
} MEMORY_BLOCK, *PMEMORY_BLOCK;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Global Variables:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// First element of the memory block list.
|
||||
PMEMORY_BLOCK g_pMemoryBlocks;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID InitializeBuffer(VOID)
|
||||
{
|
||||
// Nothing to do for now.
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID UninitializeBuffer(VOID)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
|
||||
g_pMemoryBlocks = NULL;
|
||||
|
||||
while (pBlock)
|
||||
{
|
||||
PMEMORY_BLOCK pNext = pBlock->pNext;
|
||||
VirtualFree(pBlock, 0, MEM_RELEASE);
|
||||
pBlock = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
|
||||
{
|
||||
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
|
||||
|
||||
// Round down to the allocation granularity.
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
|
||||
// Start from the previous allocation granularity multiply.
|
||||
tryAddr -= dwAllocationGranularity;
|
||||
|
||||
while (tryAddr >= (ULONG_PTR)pMinAddr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
|
||||
break;
|
||||
|
||||
if (mbi.State == MEM_FREE)
|
||||
return (LPVOID)tryAddr;
|
||||
|
||||
if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
|
||||
break;
|
||||
|
||||
tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
|
||||
{
|
||||
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
|
||||
|
||||
// Round down to the allocation granularity.
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
|
||||
// Start from the next allocation granularity multiply.
|
||||
tryAddr += dwAllocationGranularity;
|
||||
|
||||
while (tryAddr <= (ULONG_PTR)pMaxAddr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
|
||||
break;
|
||||
|
||||
if (mbi.State == MEM_FREE)
|
||||
return (LPVOID)tryAddr;
|
||||
|
||||
tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
|
||||
|
||||
// Round up to the next allocation granularity.
|
||||
tryAddr += dwAllocationGranularity - 1;
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
ULONG_PTR minAddr;
|
||||
ULONG_PTR maxAddr;
|
||||
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
|
||||
maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
|
||||
|
||||
// pOrigin ± 512MB
|
||||
if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
|
||||
minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
|
||||
|
||||
if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
|
||||
maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
|
||||
|
||||
// Make room for MEMORY_BLOCK_SIZE bytes.
|
||||
maxAddr -= MEMORY_BLOCK_SIZE - 1;
|
||||
#endif
|
||||
|
||||
// Look the registered blocks for a reachable one.
|
||||
for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Ignore the blocks too far.
|
||||
if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
|
||||
continue;
|
||||
#endif
|
||||
// The block has at least one unused slot.
|
||||
if (pBlock->pFree != NULL)
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Alloc a new block above if not found.
|
||||
{
|
||||
LPVOID pAlloc = pOrigin;
|
||||
while ((ULONG_PTR)pAlloc >= minAddr)
|
||||
{
|
||||
pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
|
||||
if (pAlloc == NULL)
|
||||
break;
|
||||
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (pBlock != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Alloc a new block below if not found.
|
||||
if (pBlock == NULL)
|
||||
{
|
||||
LPVOID pAlloc = pOrigin;
|
||||
while ((ULONG_PTR)pAlloc <= maxAddr)
|
||||
{
|
||||
pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
|
||||
if (pAlloc == NULL)
|
||||
break;
|
||||
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (pBlock != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// In x86 mode, a memory block can be placed anywhere.
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
#endif
|
||||
|
||||
if (pBlock != NULL)
|
||||
{
|
||||
// Build a linked list of all the slots.
|
||||
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
|
||||
pBlock->pFree = NULL;
|
||||
pBlock->usedCount = 0;
|
||||
do
|
||||
{
|
||||
pSlot->pNext = pBlock->pFree;
|
||||
pBlock->pFree = pSlot;
|
||||
pSlot++;
|
||||
} while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
|
||||
|
||||
pBlock->pNext = g_pMemoryBlocks;
|
||||
g_pMemoryBlocks = pBlock;
|
||||
}
|
||||
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
LPVOID AllocateBuffer(LPVOID pOrigin)
|
||||
{
|
||||
PMEMORY_SLOT pSlot;
|
||||
PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
|
||||
if (pBlock == NULL)
|
||||
return NULL;
|
||||
|
||||
// Remove an unused slot from the list.
|
||||
pSlot = pBlock->pFree;
|
||||
pBlock->pFree = pSlot->pNext;
|
||||
pBlock->usedCount++;
|
||||
#ifdef _DEBUG
|
||||
// Fill the slot with INT3 for debugging.
|
||||
memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
|
||||
#endif
|
||||
return pSlot;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID FreeBuffer(LPVOID pBuffer)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
|
||||
PMEMORY_BLOCK pPrev = NULL;
|
||||
ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
|
||||
|
||||
while (pBlock != NULL)
|
||||
{
|
||||
if ((ULONG_PTR)pBlock == pTargetBlock)
|
||||
{
|
||||
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
|
||||
#ifdef _DEBUG
|
||||
// Clear the released slot for debugging.
|
||||
memset(pSlot, 0x00, sizeof(MEMORY_SLOT));
|
||||
#endif
|
||||
// Restore the released slot to the list.
|
||||
pSlot->pNext = pBlock->pFree;
|
||||
pBlock->pFree = pSlot;
|
||||
pBlock->usedCount--;
|
||||
|
||||
// Free if unused.
|
||||
if (pBlock->usedCount == 0)
|
||||
{
|
||||
if (pPrev)
|
||||
pPrev->pNext = pBlock->pNext;
|
||||
else
|
||||
g_pMemoryBlocks = pBlock->pNext;
|
||||
|
||||
VirtualFree(pBlock, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
pPrev = pBlock;
|
||||
pBlock = pBlock->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
BOOL IsExecutableAddress(LPVOID pAddress)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mi;
|
||||
VirtualQuery(pAddress, &mi, sizeof(mi));
|
||||
|
||||
return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Size of each memory slot.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define MEMORY_SLOT_SIZE 64
|
||||
#else
|
||||
#define MEMORY_SLOT_SIZE 32
|
||||
#endif
|
||||
|
||||
VOID InitializeBuffer(VOID);
|
||||
VOID UninitializeBuffer(VOID);
|
||||
LPVOID AllocateBuffer(LPVOID pOrigin);
|
||||
VOID FreeBuffer(LPVOID pBuffer);
|
||||
BOOL IsExecutableAddress(LPVOID pAddress);
|
@ -1,324 +0,0 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 32 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
|
||||
#include <string.h>
|
||||
#include "hde32.h"
|
||||
#include "table32.h"
|
||||
|
||||
unsigned int hde32_disasm(const void *code, hde32s *hs)
|
||||
{
|
||||
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
|
||||
uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
|
||||
|
||||
memset(hs, 0, sizeof(hde32s));
|
||||
|
||||
for (x = 16; x; x--)
|
||||
switch (c = *p++) {
|
||||
case 0xf3:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F3;
|
||||
break;
|
||||
case 0xf2:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F2;
|
||||
break;
|
||||
case 0xf0:
|
||||
hs->p_lock = c;
|
||||
pref |= PRE_LOCK;
|
||||
break;
|
||||
case 0x26: case 0x2e: case 0x36:
|
||||
case 0x3e: case 0x64: case 0x65:
|
||||
hs->p_seg = c;
|
||||
pref |= PRE_SEG;
|
||||
break;
|
||||
case 0x66:
|
||||
hs->p_66 = c;
|
||||
pref |= PRE_66;
|
||||
break;
|
||||
case 0x67:
|
||||
hs->p_67 = c;
|
||||
pref |= PRE_67;
|
||||
break;
|
||||
default:
|
||||
goto pref_done;
|
||||
}
|
||||
pref_done:
|
||||
|
||||
hs->flags = (uint32_t)pref << 23;
|
||||
|
||||
if (!pref)
|
||||
pref |= PRE_NONE;
|
||||
|
||||
if ((hs->opcode = c) == 0x0f) {
|
||||
hs->opcode2 = c = *p++;
|
||||
ht += DELTA_OPCODES;
|
||||
} else if (c >= 0xa0 && c <= 0xa3) {
|
||||
if (pref & PRE_67)
|
||||
pref |= PRE_66;
|
||||
else
|
||||
pref &= ~PRE_66;
|
||||
}
|
||||
|
||||
opcode = c;
|
||||
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
||||
|
||||
if (cflags == C_ERROR) {
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
cflags = 0;
|
||||
if ((opcode & -3) == 0x24)
|
||||
cflags++;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
if (cflags & C_GROUP) {
|
||||
uint16_t t;
|
||||
t = *(uint16_t *)(ht + (cflags & 0x7f));
|
||||
cflags = (uint8_t)t;
|
||||
x = (uint8_t)(t >> 8);
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
ht = hde32_table + DELTA_PREFIXES;
|
||||
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (cflags & C_MODRM) {
|
||||
hs->flags |= F_MODRM;
|
||||
hs->modrm = c = *p++;
|
||||
hs->modrm_mod = m_mod = c >> 6;
|
||||
hs->modrm_rm = m_rm = c & 7;
|
||||
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
||||
|
||||
if (x && ((x << m_reg) & 0x80))
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
|
||||
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
|
||||
uint8_t t = opcode - 0xd9;
|
||||
if (m_mod == 3) {
|
||||
ht = hde32_table + DELTA_FPU_MODRM + t*8;
|
||||
t = ht[m_reg] << m_rm;
|
||||
} else {
|
||||
ht = hde32_table + DELTA_FPU_REG;
|
||||
t = ht[t] << m_reg;
|
||||
}
|
||||
if (t & 0x80)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (pref & PRE_LOCK) {
|
||||
if (m_mod == 3) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
} else {
|
||||
uint8_t *table_end, op = opcode;
|
||||
if (hs->opcode2) {
|
||||
ht = hde32_table + DELTA_OP2_LOCK_OK;
|
||||
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
||||
} else {
|
||||
ht = hde32_table + DELTA_OP_LOCK_OK;
|
||||
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
||||
op &= -2;
|
||||
}
|
||||
for (; ht != table_end; ht++)
|
||||
if (*ht++ == op) {
|
||||
if (!((*ht << m_reg) & 0x80))
|
||||
goto no_lock_error;
|
||||
else
|
||||
break;
|
||||
}
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
no_lock_error:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x20: case 0x22:
|
||||
m_mod = 3;
|
||||
if (m_reg > 4 || m_reg == 1)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x21: case 0x23:
|
||||
m_mod = 3;
|
||||
if (m_reg == 4 || m_reg == 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
} else {
|
||||
switch (opcode) {
|
||||
case 0x8c:
|
||||
if (m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x8e:
|
||||
if (m_reg == 1 || m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mod == 3) {
|
||||
uint8_t *table_end;
|
||||
if (hs->opcode2) {
|
||||
ht = hde32_table + DELTA_OP2_ONLY_MEM;
|
||||
table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
|
||||
} else {
|
||||
ht = hde32_table + DELTA_OP_ONLY_MEM;
|
||||
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
||||
}
|
||||
for (; ht != table_end; ht += 2)
|
||||
if (*ht++ == opcode) {
|
||||
if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
|
||||
goto error_operand;
|
||||
else
|
||||
break;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x50: case 0xd7: case 0xf7:
|
||||
if (pref & (PRE_NONE | PRE_66))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xd6:
|
||||
if (pref & (PRE_F2 | PRE_F3))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xc5:
|
||||
goto error_operand;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else
|
||||
goto no_error_operand;
|
||||
|
||||
error_operand:
|
||||
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
||||
no_error_operand:
|
||||
|
||||
c = *p++;
|
||||
if (m_reg <= 1) {
|
||||
if (opcode == 0xf6)
|
||||
cflags |= C_IMM8;
|
||||
else if (opcode == 0xf7)
|
||||
cflags |= C_IMM_P66;
|
||||
}
|
||||
|
||||
switch (m_mod) {
|
||||
case 0:
|
||||
if (pref & PRE_67) {
|
||||
if (m_rm == 6)
|
||||
disp_size = 2;
|
||||
} else
|
||||
if (m_rm == 5)
|
||||
disp_size = 4;
|
||||
break;
|
||||
case 1:
|
||||
disp_size = 1;
|
||||
break;
|
||||
case 2:
|
||||
disp_size = 2;
|
||||
if (!(pref & PRE_67))
|
||||
disp_size <<= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
|
||||
hs->flags |= F_SIB;
|
||||
p++;
|
||||
hs->sib = c;
|
||||
hs->sib_scale = c >> 6;
|
||||
hs->sib_index = (c & 0x3f) >> 3;
|
||||
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
||||
disp_size = 4;
|
||||
}
|
||||
|
||||
p--;
|
||||
switch (disp_size) {
|
||||
case 1:
|
||||
hs->flags |= F_DISP8;
|
||||
hs->disp.disp8 = *p;
|
||||
break;
|
||||
case 2:
|
||||
hs->flags |= F_DISP16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
break;
|
||||
case 4:
|
||||
hs->flags |= F_DISP32;
|
||||
hs->disp.disp32 = *(uint32_t *)p;
|
||||
break;
|
||||
}
|
||||
p += disp_size;
|
||||
} else if (pref & PRE_LOCK)
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
|
||||
if (cflags & C_IMM_P66) {
|
||||
if (cflags & C_REL32) {
|
||||
if (pref & PRE_66) {
|
||||
hs->flags |= F_IMM16 | F_RELATIVE;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
goto disasm_done;
|
||||
}
|
||||
goto rel32_ok;
|
||||
}
|
||||
if (pref & PRE_66) {
|
||||
hs->flags |= F_IMM16;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
} else {
|
||||
hs->flags |= F_IMM32;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (cflags & C_IMM16) {
|
||||
if (hs->flags & F_IMM32) {
|
||||
hs->flags |= F_IMM16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
} else if (hs->flags & F_IMM16) {
|
||||
hs->flags |= F_2IMM16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
} else {
|
||||
hs->flags |= F_IMM16;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
}
|
||||
p += 2;
|
||||
}
|
||||
if (cflags & C_IMM8) {
|
||||
hs->flags |= F_IMM8;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
if (cflags & C_REL32) {
|
||||
rel32_ok:
|
||||
hs->flags |= F_IMM32 | F_RELATIVE;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
} else if (cflags & C_REL8) {
|
||||
hs->flags |= F_IMM8 | F_RELATIVE;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
disasm_done:
|
||||
|
||||
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
||||
hs->len = 15;
|
||||
}
|
||||
|
||||
return (unsigned int)hs->len;
|
||||
}
|
||||
|
||||
#endif // defined(_M_IX86) || defined(__i386__)
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 32
|
||||
* Copyright (c) 2006-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
* hde32.h: C/C++ header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HDE32_H_
|
||||
#define _HDE32_H_
|
||||
|
||||
/* stdint.h - C99 standard header
|
||||
* http://en.wikipedia.org/wiki/stdint.h
|
||||
*
|
||||
* if your compiler doesn't contain "stdint.h" header (for
|
||||
* example, Microsoft Visual C++), you can download file:
|
||||
* http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
* and change next line to:
|
||||
* #include "pstdint.h"
|
||||
*/
|
||||
#include "pstdint.h"
|
||||
|
||||
#define F_MODRM 0x00000001
|
||||
#define F_SIB 0x00000002
|
||||
#define F_IMM8 0x00000004
|
||||
#define F_IMM16 0x00000008
|
||||
#define F_IMM32 0x00000010
|
||||
#define F_DISP8 0x00000020
|
||||
#define F_DISP16 0x00000040
|
||||
#define F_DISP32 0x00000080
|
||||
#define F_RELATIVE 0x00000100
|
||||
#define F_2IMM16 0x00000800
|
||||
#define F_ERROR 0x00001000
|
||||
#define F_ERROR_OPCODE 0x00002000
|
||||
#define F_ERROR_LENGTH 0x00004000
|
||||
#define F_ERROR_LOCK 0x00008000
|
||||
#define F_ERROR_OPERAND 0x00010000
|
||||
#define F_PREFIX_REPNZ 0x01000000
|
||||
#define F_PREFIX_REPX 0x02000000
|
||||
#define F_PREFIX_REP 0x03000000
|
||||
#define F_PREFIX_66 0x04000000
|
||||
#define F_PREFIX_67 0x08000000
|
||||
#define F_PREFIX_LOCK 0x10000000
|
||||
#define F_PREFIX_SEG 0x20000000
|
||||
#define F_PREFIX_ANY 0x3f000000
|
||||
|
||||
#define PREFIX_SEGMENT_CS 0x2e
|
||||
#define PREFIX_SEGMENT_SS 0x36
|
||||
#define PREFIX_SEGMENT_DS 0x3e
|
||||
#define PREFIX_SEGMENT_ES 0x26
|
||||
#define PREFIX_SEGMENT_FS 0x64
|
||||
#define PREFIX_SEGMENT_GS 0x65
|
||||
#define PREFIX_LOCK 0xf0
|
||||
#define PREFIX_REPNZ 0xf2
|
||||
#define PREFIX_REPX 0xf3
|
||||
#define PREFIX_OPERAND_SIZE 0x66
|
||||
#define PREFIX_ADDRESS_SIZE 0x67
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t len;
|
||||
uint8_t p_rep;
|
||||
uint8_t p_lock;
|
||||
uint8_t p_seg;
|
||||
uint8_t p_66;
|
||||
uint8_t p_67;
|
||||
uint8_t opcode;
|
||||
uint8_t opcode2;
|
||||
uint8_t modrm;
|
||||
uint8_t modrm_mod;
|
||||
uint8_t modrm_reg;
|
||||
uint8_t modrm_rm;
|
||||
uint8_t sib;
|
||||
uint8_t sib_scale;
|
||||
uint8_t sib_index;
|
||||
uint8_t sib_base;
|
||||
union {
|
||||
uint8_t imm8;
|
||||
uint16_t imm16;
|
||||
uint32_t imm32;
|
||||
} imm;
|
||||
union {
|
||||
uint8_t disp8;
|
||||
uint16_t disp16;
|
||||
uint32_t disp32;
|
||||
} disp;
|
||||
uint32_t flags;
|
||||
} hde32s;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* __cdecl */
|
||||
unsigned int hde32_disasm(const void *code, hde32s *hs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HDE32_H_ */
|
@ -1,333 +0,0 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
|
||||
#include <string.h>
|
||||
#include "hde64.h"
|
||||
#include "table64.h"
|
||||
|
||||
unsigned int hde64_disasm(const void *code, hde64s *hs)
|
||||
{
|
||||
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
|
||||
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
|
||||
uint8_t op64 = 0;
|
||||
|
||||
memset(hs, 0, sizeof(hde64s));
|
||||
|
||||
for (x = 16; x; x--)
|
||||
switch (c = *p++) {
|
||||
case 0xf3:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F3;
|
||||
break;
|
||||
case 0xf2:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F2;
|
||||
break;
|
||||
case 0xf0:
|
||||
hs->p_lock = c;
|
||||
pref |= PRE_LOCK;
|
||||
break;
|
||||
case 0x26: case 0x2e: case 0x36:
|
||||
case 0x3e: case 0x64: case 0x65:
|
||||
hs->p_seg = c;
|
||||
pref |= PRE_SEG;
|
||||
break;
|
||||
case 0x66:
|
||||
hs->p_66 = c;
|
||||
pref |= PRE_66;
|
||||
break;
|
||||
case 0x67:
|
||||
hs->p_67 = c;
|
||||
pref |= PRE_67;
|
||||
break;
|
||||
default:
|
||||
goto pref_done;
|
||||
}
|
||||
pref_done:
|
||||
|
||||
hs->flags = (uint32_t)pref << 23;
|
||||
|
||||
if (!pref)
|
||||
pref |= PRE_NONE;
|
||||
|
||||
if ((c & 0xf0) == 0x40) {
|
||||
hs->flags |= F_PREFIX_REX;
|
||||
if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
|
||||
op64++;
|
||||
hs->rex_r = (c & 7) >> 2;
|
||||
hs->rex_x = (c & 3) >> 1;
|
||||
hs->rex_b = c & 1;
|
||||
if (((c = *p++) & 0xf0) == 0x40) {
|
||||
opcode = c;
|
||||
goto error_opcode;
|
||||
}
|
||||
}
|
||||
|
||||
if ((hs->opcode = c) == 0x0f) {
|
||||
hs->opcode2 = c = *p++;
|
||||
ht += DELTA_OPCODES;
|
||||
} else if (c >= 0xa0 && c <= 0xa3) {
|
||||
op64++;
|
||||
if (pref & PRE_67)
|
||||
pref |= PRE_66;
|
||||
else
|
||||
pref &= ~PRE_66;
|
||||
}
|
||||
|
||||
opcode = c;
|
||||
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
||||
|
||||
if (cflags == C_ERROR) {
|
||||
error_opcode:
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
cflags = 0;
|
||||
if ((opcode & -3) == 0x24)
|
||||
cflags++;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
if (cflags & C_GROUP) {
|
||||
uint16_t t;
|
||||
t = *(uint16_t *)(ht + (cflags & 0x7f));
|
||||
cflags = (uint8_t)t;
|
||||
x = (uint8_t)(t >> 8);
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_PREFIXES;
|
||||
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (cflags & C_MODRM) {
|
||||
hs->flags |= F_MODRM;
|
||||
hs->modrm = c = *p++;
|
||||
hs->modrm_mod = m_mod = c >> 6;
|
||||
hs->modrm_rm = m_rm = c & 7;
|
||||
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
||||
|
||||
if (x && ((x << m_reg) & 0x80))
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
|
||||
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
|
||||
uint8_t t = opcode - 0xd9;
|
||||
if (m_mod == 3) {
|
||||
ht = hde64_table + DELTA_FPU_MODRM + t*8;
|
||||
t = ht[m_reg] << m_rm;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_FPU_REG;
|
||||
t = ht[t] << m_reg;
|
||||
}
|
||||
if (t & 0x80)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (pref & PRE_LOCK) {
|
||||
if (m_mod == 3) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
} else {
|
||||
uint8_t *table_end, op = opcode;
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_OP2_LOCK_OK;
|
||||
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_OP_LOCK_OK;
|
||||
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
||||
op &= -2;
|
||||
}
|
||||
for (; ht != table_end; ht++)
|
||||
if (*ht++ == op) {
|
||||
if (!((*ht << m_reg) & 0x80))
|
||||
goto no_lock_error;
|
||||
else
|
||||
break;
|
||||
}
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
no_lock_error:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x20: case 0x22:
|
||||
m_mod = 3;
|
||||
if (m_reg > 4 || m_reg == 1)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x21: case 0x23:
|
||||
m_mod = 3;
|
||||
if (m_reg == 4 || m_reg == 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
} else {
|
||||
switch (opcode) {
|
||||
case 0x8c:
|
||||
if (m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x8e:
|
||||
if (m_reg == 1 || m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mod == 3) {
|
||||
uint8_t *table_end;
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_OP2_ONLY_MEM;
|
||||
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_OP_ONLY_MEM;
|
||||
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
||||
}
|
||||
for (; ht != table_end; ht += 2)
|
||||
if (*ht++ == opcode) {
|
||||
if (*ht++ & pref && !((*ht << m_reg) & 0x80))
|
||||
goto error_operand;
|
||||
else
|
||||
break;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x50: case 0xd7: case 0xf7:
|
||||
if (pref & (PRE_NONE | PRE_66))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xd6:
|
||||
if (pref & (PRE_F2 | PRE_F3))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xc5:
|
||||
goto error_operand;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else
|
||||
goto no_error_operand;
|
||||
|
||||
error_operand:
|
||||
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
||||
no_error_operand:
|
||||
|
||||
c = *p++;
|
||||
if (m_reg <= 1) {
|
||||
if (opcode == 0xf6)
|
||||
cflags |= C_IMM8;
|
||||
else if (opcode == 0xf7)
|
||||
cflags |= C_IMM_P66;
|
||||
}
|
||||
|
||||
switch (m_mod) {
|
||||
case 0:
|
||||
if (pref & PRE_67) {
|
||||
if (m_rm == 6)
|
||||
disp_size = 2;
|
||||
} else
|
||||
if (m_rm == 5)
|
||||
disp_size = 4;
|
||||
break;
|
||||
case 1:
|
||||
disp_size = 1;
|
||||
break;
|
||||
case 2:
|
||||
disp_size = 2;
|
||||
if (!(pref & PRE_67))
|
||||
disp_size <<= 1;
|
||||
}
|
||||
|
||||
if (m_mod != 3 && m_rm == 4) {
|
||||
hs->flags |= F_SIB;
|
||||
p++;
|
||||
hs->sib = c;
|
||||
hs->sib_scale = c >> 6;
|
||||
hs->sib_index = (c & 0x3f) >> 3;
|
||||
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
||||
disp_size = 4;
|
||||
}
|
||||
|
||||
p--;
|
||||
switch (disp_size) {
|
||||
case 1:
|
||||
hs->flags |= F_DISP8;
|
||||
hs->disp.disp8 = *p;
|
||||
break;
|
||||
case 2:
|
||||
hs->flags |= F_DISP16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
break;
|
||||
case 4:
|
||||
hs->flags |= F_DISP32;
|
||||
hs->disp.disp32 = *(uint32_t *)p;
|
||||
}
|
||||
p += disp_size;
|
||||
} else if (pref & PRE_LOCK)
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
|
||||
if (cflags & C_IMM_P66) {
|
||||
if (cflags & C_REL32) {
|
||||
if (pref & PRE_66) {
|
||||
hs->flags |= F_IMM16 | F_RELATIVE;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
goto disasm_done;
|
||||
}
|
||||
goto rel32_ok;
|
||||
}
|
||||
if (op64) {
|
||||
hs->flags |= F_IMM64;
|
||||
hs->imm.imm64 = *(uint64_t *)p;
|
||||
p += 8;
|
||||
} else if (!(pref & PRE_66)) {
|
||||
hs->flags |= F_IMM32;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
} else
|
||||
goto imm16_ok;
|
||||
}
|
||||
|
||||
|
||||
if (cflags & C_IMM16) {
|
||||
imm16_ok:
|
||||
hs->flags |= F_IMM16;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
}
|
||||
if (cflags & C_IMM8) {
|
||||
hs->flags |= F_IMM8;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
if (cflags & C_REL32) {
|
||||
rel32_ok:
|
||||
hs->flags |= F_IMM32 | F_RELATIVE;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
} else if (cflags & C_REL8) {
|
||||
hs->flags |= F_IMM8 | F_RELATIVE;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
disasm_done:
|
||||
|
||||
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
||||
hs->len = 15;
|
||||
}
|
||||
|
||||
return (unsigned int)hs->len;
|
||||
}
|
||||
|
||||
#endif // defined(_M_X64) || defined(__x86_64__)
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
* hde64.h: C/C++ header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HDE64_H_
|
||||
#define _HDE64_H_
|
||||
|
||||
/* stdint.h - C99 standard header
|
||||
* http://en.wikipedia.org/wiki/stdint.h
|
||||
*
|
||||
* if your compiler doesn't contain "stdint.h" header (for
|
||||
* example, Microsoft Visual C++), you can download file:
|
||||
* http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
* and change next line to:
|
||||
* #include "pstdint.h"
|
||||
*/
|
||||
#include "pstdint.h"
|
||||
|
||||
#define F_MODRM 0x00000001
|
||||
#define F_SIB 0x00000002
|
||||
#define F_IMM8 0x00000004
|
||||
#define F_IMM16 0x00000008
|
||||
#define F_IMM32 0x00000010
|
||||
#define F_IMM64 0x00000020
|
||||
#define F_DISP8 0x00000040
|
||||
#define F_DISP16 0x00000080
|
||||
#define F_DISP32 0x00000100
|
||||
#define F_RELATIVE 0x00000200
|
||||
#define F_ERROR 0x00001000
|
||||
#define F_ERROR_OPCODE 0x00002000
|
||||
#define F_ERROR_LENGTH 0x00004000
|
||||
#define F_ERROR_LOCK 0x00008000
|
||||
#define F_ERROR_OPERAND 0x00010000
|
||||
#define F_PREFIX_REPNZ 0x01000000
|
||||
#define F_PREFIX_REPX 0x02000000
|
||||
#define F_PREFIX_REP 0x03000000
|
||||
#define F_PREFIX_66 0x04000000
|
||||
#define F_PREFIX_67 0x08000000
|
||||
#define F_PREFIX_LOCK 0x10000000
|
||||
#define F_PREFIX_SEG 0x20000000
|
||||
#define F_PREFIX_REX 0x40000000
|
||||
#define F_PREFIX_ANY 0x7f000000
|
||||
|
||||
#define PREFIX_SEGMENT_CS 0x2e
|
||||
#define PREFIX_SEGMENT_SS 0x36
|
||||
#define PREFIX_SEGMENT_DS 0x3e
|
||||
#define PREFIX_SEGMENT_ES 0x26
|
||||
#define PREFIX_SEGMENT_FS 0x64
|
||||
#define PREFIX_SEGMENT_GS 0x65
|
||||
#define PREFIX_LOCK 0xf0
|
||||
#define PREFIX_REPNZ 0xf2
|
||||
#define PREFIX_REPX 0xf3
|
||||
#define PREFIX_OPERAND_SIZE 0x66
|
||||
#define PREFIX_ADDRESS_SIZE 0x67
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t len;
|
||||
uint8_t p_rep;
|
||||
uint8_t p_lock;
|
||||
uint8_t p_seg;
|
||||
uint8_t p_66;
|
||||
uint8_t p_67;
|
||||
uint8_t rex;
|
||||
uint8_t rex_w;
|
||||
uint8_t rex_r;
|
||||
uint8_t rex_x;
|
||||
uint8_t rex_b;
|
||||
uint8_t opcode;
|
||||
uint8_t opcode2;
|
||||
uint8_t modrm;
|
||||
uint8_t modrm_mod;
|
||||
uint8_t modrm_reg;
|
||||
uint8_t modrm_rm;
|
||||
uint8_t sib;
|
||||
uint8_t sib_scale;
|
||||
uint8_t sib_index;
|
||||
uint8_t sib_base;
|
||||
union {
|
||||
uint8_t imm8;
|
||||
uint16_t imm16;
|
||||
uint32_t imm32;
|
||||
uint64_t imm64;
|
||||
} imm;
|
||||
union {
|
||||
uint8_t disp8;
|
||||
uint16_t disp16;
|
||||
uint32_t disp32;
|
||||
} disp;
|
||||
uint32_t flags;
|
||||
} hde64s;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* __cdecl */
|
||||
unsigned int hde64_disasm(const void *code, hde64s *hs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HDE64_H_ */
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// Integer types for HDE.
|
||||
typedef INT8 int8_t;
|
||||
typedef INT16 int16_t;
|
||||
typedef INT32 int32_t;
|
||||
typedef INT64 int64_t;
|
||||
typedef UINT8 uint8_t;
|
||||
typedef UINT16 uint16_t;
|
||||
typedef UINT32 uint32_t;
|
||||
typedef UINT64 uint64_t;
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 32 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#define C_NONE 0x00
|
||||
#define C_MODRM 0x01
|
||||
#define C_IMM8 0x02
|
||||
#define C_IMM16 0x04
|
||||
#define C_IMM_P66 0x10
|
||||
#define C_REL8 0x20
|
||||
#define C_REL32 0x40
|
||||
#define C_GROUP 0x80
|
||||
#define C_ERROR 0xff
|
||||
|
||||
#define PRE_ANY 0x00
|
||||
#define PRE_NONE 0x01
|
||||
#define PRE_F2 0x02
|
||||
#define PRE_F3 0x04
|
||||
#define PRE_66 0x08
|
||||
#define PRE_67 0x10
|
||||
#define PRE_LOCK 0x20
|
||||
#define PRE_SEG 0x40
|
||||
#define PRE_ALL 0xff
|
||||
|
||||
#define DELTA_OPCODES 0x4a
|
||||
#define DELTA_FPU_REG 0xf1
|
||||
#define DELTA_FPU_MODRM 0xf8
|
||||
#define DELTA_PREFIXES 0x130
|
||||
#define DELTA_OP_LOCK_OK 0x1a1
|
||||
#define DELTA_OP2_LOCK_OK 0x1b9
|
||||
#define DELTA_OP_ONLY_MEM 0x1cb
|
||||
#define DELTA_OP2_ONLY_MEM 0x1da
|
||||
|
||||
unsigned char hde32_table[] = {
|
||||
0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,
|
||||
0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,
|
||||
0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,
|
||||
0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,
|
||||
0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,
|
||||
0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,
|
||||
0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,
|
||||
0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,
|
||||
0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,
|
||||
0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,
|
||||
0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,
|
||||
0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,
|
||||
0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,
|
||||
0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,
|
||||
0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,
|
||||
0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,
|
||||
0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,
|
||||
0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,
|
||||
0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,
|
||||
0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,
|
||||
0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,
|
||||
0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,
|
||||
0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,
|
||||
0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
|
||||
0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,
|
||||
0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,
|
||||
0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,
|
||||
0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,
|
||||
0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,
|
||||
0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,
|
||||
0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,
|
||||
0xe7,0x08,0x00,0xf0,0x02,0x00
|
||||
};
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#define C_NONE 0x00
|
||||
#define C_MODRM 0x01
|
||||
#define C_IMM8 0x02
|
||||
#define C_IMM16 0x04
|
||||
#define C_IMM_P66 0x10
|
||||
#define C_REL8 0x20
|
||||
#define C_REL32 0x40
|
||||
#define C_GROUP 0x80
|
||||
#define C_ERROR 0xff
|
||||
|
||||
#define PRE_ANY 0x00
|
||||
#define PRE_NONE 0x01
|
||||
#define PRE_F2 0x02
|
||||
#define PRE_F3 0x04
|
||||
#define PRE_66 0x08
|
||||
#define PRE_67 0x10
|
||||
#define PRE_LOCK 0x20
|
||||
#define PRE_SEG 0x40
|
||||
#define PRE_ALL 0xff
|
||||
|
||||
#define DELTA_OPCODES 0x4a
|
||||
#define DELTA_FPU_REG 0xfd
|
||||
#define DELTA_FPU_MODRM 0x104
|
||||
#define DELTA_PREFIXES 0x13c
|
||||
#define DELTA_OP_LOCK_OK 0x1ae
|
||||
#define DELTA_OP2_LOCK_OK 0x1c6
|
||||
#define DELTA_OP_ONLY_MEM 0x1d8
|
||||
#define DELTA_OP2_ONLY_MEM 0x1e7
|
||||
|
||||
unsigned char hde64_table[] = {
|
||||
0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
|
||||
0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
|
||||
0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
|
||||
0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
|
||||
0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
|
||||
0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
|
||||
0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
|
||||
0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
|
||||
0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
|
||||
0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
|
||||
0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
|
||||
0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
|
||||
0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
|
||||
0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
|
||||
0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
|
||||
0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
|
||||
0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
|
||||
0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
|
||||
0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
|
||||
0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
|
||||
0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||
0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
|
||||
0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
|
||||
0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
|
||||
0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
|
||||
0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
|
||||
0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
|
||||
0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
|
||||
0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
|
||||
0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
|
||||
0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
|
||||
0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
|
||||
0x00,0xf0,0x02,0x00
|
||||
};
|
@ -1,889 +0,0 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "../include/MinHook.h"
|
||||
#include "buffer.h"
|
||||
#include "trampoline.h"
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
#endif
|
||||
|
||||
// Initial capacity of the HOOK_ENTRY buffer.
|
||||
#define INITIAL_HOOK_CAPACITY 32
|
||||
|
||||
// Initial capacity of the thread IDs buffer.
|
||||
#define INITIAL_THREAD_CAPACITY 128
|
||||
|
||||
// Special hook position values.
|
||||
#define INVALID_HOOK_POS UINT_MAX
|
||||
#define ALL_HOOKS_POS UINT_MAX
|
||||
|
||||
// Freeze() action argument defines.
|
||||
#define ACTION_DISABLE 0
|
||||
#define ACTION_ENABLE 1
|
||||
#define ACTION_APPLY_QUEUED 2
|
||||
|
||||
// Thread access rights for suspending/resuming threads.
|
||||
#define THREAD_ACCESS \
|
||||
(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)
|
||||
|
||||
// Hook information.
|
||||
typedef struct _HOOK_ENTRY
|
||||
{
|
||||
LPVOID pTarget; // Address of the target function.
|
||||
LPVOID pDetour; // Address of the detour or relay function.
|
||||
LPVOID pTrampoline; // Address of the trampoline function.
|
||||
UINT8 backup[8]; // Original prologue of the target function.
|
||||
|
||||
UINT8 patchAbove : 1; // Uses the hot patch area.
|
||||
UINT8 isEnabled : 1; // Enabled.
|
||||
UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
|
||||
|
||||
UINT nIP : 4; // Count of the instruction boundaries.
|
||||
UINT8 oldIPs[8]; // Instruction boundaries of the target function.
|
||||
UINT8 newIPs[8]; // Instruction boundaries of the trampoline function.
|
||||
} HOOK_ENTRY, *PHOOK_ENTRY;
|
||||
|
||||
// Suspended threads for Freeze()/Unfreeze().
|
||||
typedef struct _FROZEN_THREADS
|
||||
{
|
||||
LPDWORD pItems; // Data heap
|
||||
UINT capacity; // Size of allocated data heap, items
|
||||
UINT size; // Actual number of data items
|
||||
} FROZEN_THREADS, *PFROZEN_THREADS;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Global Variables:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Spin lock flag for EnterSpinLock()/LeaveSpinLock().
|
||||
volatile LONG g_isLocked = FALSE;
|
||||
|
||||
// Private heap handle. If not NULL, this library is initialized.
|
||||
HANDLE g_hHeap = NULL;
|
||||
|
||||
// Hook entries.
|
||||
struct
|
||||
{
|
||||
PHOOK_ENTRY pItems; // Data heap
|
||||
UINT capacity; // Size of allocated data heap, items
|
||||
UINT size; // Actual number of data items
|
||||
} g_hooks;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Returns INVALID_HOOK_POS if not found.
|
||||
static UINT FindHookEntry(LPVOID pTarget)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
|
||||
return i;
|
||||
}
|
||||
|
||||
return INVALID_HOOK_POS;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PHOOK_ENTRY AddHookEntry()
|
||||
{
|
||||
if (g_hooks.pItems == NULL)
|
||||
{
|
||||
g_hooks.capacity = INITIAL_HOOK_CAPACITY;
|
||||
g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
|
||||
g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
|
||||
if (g_hooks.pItems == NULL)
|
||||
return NULL;
|
||||
}
|
||||
else if (g_hooks.size >= g_hooks.capacity)
|
||||
{
|
||||
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
|
||||
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
g_hooks.capacity *= 2;
|
||||
g_hooks.pItems = p;
|
||||
}
|
||||
|
||||
return &g_hooks.pItems[g_hooks.size++];
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static void DeleteHookEntry(UINT pos)
|
||||
{
|
||||
if (pos < g_hooks.size - 1)
|
||||
g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];
|
||||
|
||||
g_hooks.size--;
|
||||
|
||||
if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
|
||||
{
|
||||
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
|
||||
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
g_hooks.capacity /= 2;
|
||||
g_hooks.pItems = p;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
|
||||
return (DWORD_PTR)pHook->pTarget;
|
||||
|
||||
for (i = 0; i < pHook->nIP; ++i)
|
||||
{
|
||||
if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
|
||||
return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Check relay function.
|
||||
if (ip == (DWORD_PTR)pHook->pDetour)
|
||||
return (DWORD_PTR)pHook->pTarget;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pHook->nIP; ++i)
|
||||
{
|
||||
if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
|
||||
return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
|
||||
{
|
||||
// If the thread suspended in the overwritten area,
|
||||
// move IP to the proper address.
|
||||
|
||||
CONTEXT c;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
DWORD64 *pIP = &c.Rip;
|
||||
#else
|
||||
DWORD *pIP = &c.Eip;
|
||||
#endif
|
||||
UINT count;
|
||||
|
||||
c.ContextFlags = CONTEXT_CONTROL;
|
||||
if (!GetThreadContext(hThread, &c))
|
||||
return;
|
||||
|
||||
if (pos == ALL_HOOKS_POS)
|
||||
{
|
||||
pos = 0;
|
||||
count = g_hooks.size;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = pos + 1;
|
||||
}
|
||||
|
||||
for (; pos < count; ++pos)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
|
||||
BOOL enable;
|
||||
DWORD_PTR ip;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_DISABLE:
|
||||
enable = FALSE;
|
||||
break;
|
||||
|
||||
case ACTION_ENABLE:
|
||||
enable = TRUE;
|
||||
break;
|
||||
|
||||
default: // ACTION_APPLY_QUEUED
|
||||
enable = pHook->queueEnable;
|
||||
break;
|
||||
}
|
||||
if (pHook->isEnabled == enable)
|
||||
continue;
|
||||
|
||||
if (enable)
|
||||
ip = FindNewIP(pHook, *pIP);
|
||||
else
|
||||
ip = FindOldIP(pHook, *pIP);
|
||||
|
||||
if (ip != 0)
|
||||
{
|
||||
*pIP = ip;
|
||||
SetThreadContext(hThread, &c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID EnumerateThreads(PFROZEN_THREADS pThreads)
|
||||
{
|
||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if (hSnapshot != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
THREADENTRY32 te;
|
||||
te.dwSize = sizeof(THREADENTRY32);
|
||||
if (Thread32First(hSnapshot, &te))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
|
||||
&& te.th32OwnerProcessID == GetCurrentProcessId()
|
||||
&& te.th32ThreadID != GetCurrentThreadId())
|
||||
{
|
||||
if (pThreads->pItems == NULL)
|
||||
{
|
||||
pThreads->capacity = INITIAL_THREAD_CAPACITY;
|
||||
pThreads->pItems
|
||||
= (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
|
||||
if (pThreads->pItems == NULL)
|
||||
break;
|
||||
}
|
||||
else if (pThreads->size >= pThreads->capacity)
|
||||
{
|
||||
LPDWORD p = (LPDWORD)HeapReAlloc(
|
||||
g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD));
|
||||
if (p == NULL)
|
||||
break;
|
||||
|
||||
pThreads->capacity *= 2;
|
||||
pThreads->pItems = p;
|
||||
}
|
||||
pThreads->pItems[pThreads->size++] = te.th32ThreadID;
|
||||
}
|
||||
|
||||
te.dwSize = sizeof(THREADENTRY32);
|
||||
} while (Thread32Next(hSnapshot, &te));
|
||||
}
|
||||
CloseHandle(hSnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
|
||||
{
|
||||
pThreads->pItems = NULL;
|
||||
pThreads->capacity = 0;
|
||||
pThreads->size = 0;
|
||||
EnumerateThreads(pThreads);
|
||||
|
||||
if (pThreads->pItems != NULL)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pThreads->size; ++i)
|
||||
{
|
||||
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
|
||||
if (hThread != NULL)
|
||||
{
|
||||
SuspendThread(hThread);
|
||||
ProcessThreadIPs(hThread, pos, action);
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID Unfreeze(PFROZEN_THREADS pThreads)
|
||||
{
|
||||
if (pThreads->pItems != NULL)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pThreads->size; ++i)
|
||||
{
|
||||
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
|
||||
if (hThread != NULL)
|
||||
{
|
||||
ResumeThread(hThread);
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
|
||||
HeapFree(g_hHeap, 0, pThreads->pItems);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
|
||||
DWORD oldProtect;
|
||||
SIZE_T patchSize = sizeof(JMP_REL);
|
||||
LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;
|
||||
|
||||
if (pHook->patchAbove)
|
||||
{
|
||||
pPatchTarget -= sizeof(JMP_REL);
|
||||
patchSize += sizeof(JMP_REL_SHORT);
|
||||
}
|
||||
|
||||
if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
|
||||
return MH_ERROR_MEMORY_PROTECT;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
|
||||
pJmp->opcode = 0xE9;
|
||||
pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
|
||||
|
||||
if (pHook->patchAbove)
|
||||
{
|
||||
PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
|
||||
pShortJmp->opcode = 0xEB;
|
||||
pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pHook->patchAbove)
|
||||
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
|
||||
else
|
||||
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
|
||||
}
|
||||
|
||||
VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);
|
||||
|
||||
// Just-in-case measure.
|
||||
FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);
|
||||
|
||||
pHook->isEnabled = enable;
|
||||
pHook->queueEnable = enable;
|
||||
|
||||
return MH_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableAllHooksLL(BOOL enable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
UINT i, first = INVALID_HOOK_POS;
|
||||
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != enable)
|
||||
{
|
||||
first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first != INVALID_HOOK_POS)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
|
||||
|
||||
for (i = first; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != enable)
|
||||
{
|
||||
status = EnableHookLL(i, enable);
|
||||
if (status != MH_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID EnterSpinLock(VOID)
|
||||
{
|
||||
SIZE_T spinCount = 0;
|
||||
|
||||
// Wait until the flag is FALSE.
|
||||
while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
|
||||
{
|
||||
// No need to generate a memory barrier here, since InterlockedCompareExchange()
|
||||
// generates a full memory barrier itself.
|
||||
|
||||
// Prevent the loop from being too busy.
|
||||
if (spinCount < 32)
|
||||
Sleep(0);
|
||||
else
|
||||
Sleep(1);
|
||||
|
||||
spinCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID LeaveSpinLock(VOID)
|
||||
{
|
||||
// No need to generate a memory barrier here, since InterlockedExchange()
|
||||
// generates a full memory barrier itself.
|
||||
|
||||
InterlockedExchange(&g_isLocked, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_Initialize(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap == NULL)
|
||||
{
|
||||
g_hHeap = HeapCreate(0, 0, 0);
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
// Initialize the internal function buffer.
|
||||
InitializeBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
status = EnableAllHooksLL(FALSE);
|
||||
if (status == MH_OK)
|
||||
{
|
||||
// Free the internal function buffer.
|
||||
|
||||
// HeapFree is actually not required, but some tools detect a false
|
||||
// memory leak without HeapFree.
|
||||
|
||||
UninitializeBuffer();
|
||||
|
||||
HeapFree(g_hHeap, 0, g_hooks.pItems);
|
||||
HeapDestroy(g_hHeap);
|
||||
|
||||
g_hHeap = NULL;
|
||||
|
||||
g_hooks.pItems = NULL;
|
||||
g_hooks.capacity = 0;
|
||||
g_hooks.size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos == INVALID_HOOK_POS)
|
||||
{
|
||||
LPVOID pBuffer = AllocateBuffer(pTarget);
|
||||
if (pBuffer != NULL)
|
||||
{
|
||||
TRAMPOLINE ct;
|
||||
|
||||
ct.pTarget = pTarget;
|
||||
ct.pDetour = pDetour;
|
||||
ct.pTrampoline = pBuffer;
|
||||
if (CreateTrampolineFunction(&ct))
|
||||
{
|
||||
PHOOK_ENTRY pHook = AddHookEntry();
|
||||
if (pHook != NULL)
|
||||
{
|
||||
pHook->pTarget = ct.pTarget;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
pHook->pDetour = ct.pRelay;
|
||||
#else
|
||||
pHook->pDetour = ct.pDetour;
|
||||
#endif
|
||||
pHook->pTrampoline = ct.pTrampoline;
|
||||
pHook->patchAbove = ct.patchAbove;
|
||||
pHook->isEnabled = FALSE;
|
||||
pHook->queueEnable = FALSE;
|
||||
pHook->nIP = ct.nIP;
|
||||
memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
|
||||
memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));
|
||||
|
||||
// Back up the target function.
|
||||
|
||||
if (ct.patchAbove)
|
||||
{
|
||||
memcpy(
|
||||
pHook->backup,
|
||||
(LPBYTE)pTarget - sizeof(JMP_REL),
|
||||
sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
|
||||
}
|
||||
|
||||
if (ppOriginal != NULL)
|
||||
*ppOriginal = pHook->pTrampoline;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
if (status != MH_OK)
|
||||
{
|
||||
FreeBuffer(pBuffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_ALREADY_CREATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_EXECUTABLE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
if (g_hooks.pItems[pos].isEnabled)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
Freeze(&threads, pos, ACTION_DISABLE);
|
||||
|
||||
status = EnableHookLL(pos, FALSE);
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
|
||||
if (status == MH_OK)
|
||||
{
|
||||
FreeBuffer(g_hooks.pItems[pos].pTrampoline);
|
||||
DeleteHookEntry(pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (pTarget == MH_ALL_HOOKS)
|
||||
{
|
||||
status = EnableAllHooksLL(enable);
|
||||
}
|
||||
else
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
if (g_hooks.pItems[pos].isEnabled != enable)
|
||||
{
|
||||
Freeze(&threads, pos, ACTION_ENABLE);
|
||||
|
||||
status = EnableHookLL(pos, enable);
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
|
||||
{
|
||||
return EnableHook(pTarget, TRUE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
|
||||
{
|
||||
return EnableHook(pTarget, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (pTarget == MH_ALL_HOOKS)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
g_hooks.pItems[i].queueEnable = queueEnable;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
g_hooks.pItems[pos].queueEnable = queueEnable;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
|
||||
{
|
||||
return QueueHook(pTarget, TRUE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
|
||||
{
|
||||
return QueueHook(pTarget, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
UINT i, first = INVALID_HOOK_POS;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
|
||||
{
|
||||
first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first != INVALID_HOOK_POS)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
|
||||
|
||||
for (i = first; i < g_hooks.size; ++i)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[i];
|
||||
if (pHook->isEnabled != pHook->queueEnable)
|
||||
{
|
||||
status = EnableHookLL(i, pHook->queueEnable);
|
||||
if (status != MH_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
|
||||
LPVOID *ppOriginal, LPVOID *ppTarget)
|
||||
{
|
||||
HMODULE hModule;
|
||||
LPVOID pTarget;
|
||||
|
||||
hModule = GetModuleHandleW(pszModule);
|
||||
if (hModule == NULL)
|
||||
return MH_ERROR_MODULE_NOT_FOUND;
|
||||
|
||||
pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
|
||||
if (pTarget == NULL)
|
||||
return MH_ERROR_FUNCTION_NOT_FOUND;
|
||||
|
||||
if(ppTarget != NULL)
|
||||
*ppTarget = pTarget;
|
||||
|
||||
return MH_CreateHook(pTarget, pDetour, ppOriginal);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
|
||||
{
|
||||
return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
const char * WINAPI MH_StatusToString(MH_STATUS status)
|
||||
{
|
||||
#define MH_ST2STR(x) \
|
||||
case x: \
|
||||
return #x;
|
||||
|
||||
switch (status) {
|
||||
MH_ST2STR(MH_UNKNOWN)
|
||||
MH_ST2STR(MH_OK)
|
||||
MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
|
||||
MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
|
||||
MH_ST2STR(MH_ERROR_ALREADY_CREATED)
|
||||
MH_ST2STR(MH_ERROR_NOT_CREATED)
|
||||
MH_ST2STR(MH_ERROR_ENABLED)
|
||||
MH_ST2STR(MH_ERROR_DISABLED)
|
||||
MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
|
||||
MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
|
||||
MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
|
||||
MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
|
||||
MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
|
||||
MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
|
||||
}
|
||||
|
||||
#undef MH_ST2STR
|
||||
|
||||
return "(unknown)";
|
||||
}
|
@ -1,320 +0,0 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
#endif
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#include "./hde/hde64.h"
|
||||
typedef hde64s HDE;
|
||||
#define HDE_DISASM(code, hs) hde64_disasm(code, hs)
|
||||
#else
|
||||
#include "./hde/hde32.h"
|
||||
typedef hde32s HDE;
|
||||
#define HDE_DISASM(code, hs) hde32_disasm(code, hs)
|
||||
#endif
|
||||
|
||||
#include "trampoline.h"
|
||||
#include "buffer.h"
|
||||
|
||||
// Maximum size of a trampoline function.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
|
||||
#else
|
||||
#define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static BOOL IsCodePadding(LPBYTE pInst, UINT size)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
|
||||
return FALSE;
|
||||
|
||||
for (i = 1; i < size; ++i)
|
||||
{
|
||||
if (pInst[i] != pInst[0])
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
CALL_ABS call = {
|
||||
0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
|
||||
0xEB, 0x08, // EB 08: JMP +10
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
JMP_ABS jmp = {
|
||||
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
JCC_ABS jcc = {
|
||||
0x70, 0x0E, // 7* 0E: J** +16
|
||||
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
#else
|
||||
CALL_REL call = {
|
||||
0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
JMP_REL jmp = {
|
||||
0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
JCC_REL jcc = {
|
||||
0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
#endif
|
||||
|
||||
UINT8 oldPos = 0;
|
||||
UINT8 newPos = 0;
|
||||
ULONG_PTR jmpDest = 0; // Destination address of an internal jump.
|
||||
BOOL finished = FALSE; // Is the function completed?
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
UINT8 instBuf[16];
|
||||
#endif
|
||||
|
||||
ct->patchAbove = FALSE;
|
||||
ct->nIP = 0;
|
||||
|
||||
do
|
||||
{
|
||||
HDE hs;
|
||||
UINT copySize;
|
||||
LPVOID pCopySrc;
|
||||
ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos;
|
||||
ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;
|
||||
|
||||
copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
|
||||
if (hs.flags & F_ERROR)
|
||||
return FALSE;
|
||||
|
||||
pCopySrc = (LPVOID)pOldInst;
|
||||
if (oldPos >= sizeof(JMP_REL))
|
||||
{
|
||||
// The trampoline function is long enough.
|
||||
// Complete the function with the jump to the target function.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
jmp.address = pOldInst;
|
||||
#else
|
||||
jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));
|
||||
#endif
|
||||
pCopySrc = &jmp;
|
||||
copySize = sizeof(jmp);
|
||||
|
||||
finished = TRUE;
|
||||
}
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
else if ((hs.modrm & 0xC7) == 0x05)
|
||||
{
|
||||
// Instructions using RIP relative addressing. (ModR/M = 00???101B)
|
||||
|
||||
// Modify the RIP relative address.
|
||||
PUINT32 pRelAddr;
|
||||
|
||||
// Avoid using memcpy to reduce the footprint.
|
||||
#ifndef _MSC_VER
|
||||
memcpy(instBuf, (LPBYTE)pOldInst, copySize);
|
||||
#else
|
||||
__movsb(instBuf, (LPBYTE)pOldInst, copySize);
|
||||
#endif
|
||||
pCopySrc = instBuf;
|
||||
|
||||
// Relative address is stored at (instruction length - immediate value length - 4).
|
||||
pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
|
||||
*pRelAddr
|
||||
= (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));
|
||||
|
||||
// Complete the function if JMP (FF /4).
|
||||
if (hs.opcode == 0xFF && hs.modrm_reg == 4)
|
||||
finished = TRUE;
|
||||
}
|
||||
#endif
|
||||
else if (hs.opcode == 0xE8)
|
||||
{
|
||||
// Direct relative CALL
|
||||
ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
call.address = dest;
|
||||
#else
|
||||
call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));
|
||||
#endif
|
||||
pCopySrc = &call;
|
||||
copySize = sizeof(call);
|
||||
}
|
||||
else if ((hs.opcode & 0xFD) == 0xE9)
|
||||
{
|
||||
// Direct relative JMP (EB or E9)
|
||||
ULONG_PTR dest = pOldInst + hs.len;
|
||||
|
||||
if (hs.opcode == 0xEB) // isShort jmp
|
||||
dest += (INT8)hs.imm.imm8;
|
||||
else
|
||||
dest += (INT32)hs.imm.imm32;
|
||||
|
||||
// Simply copy an internal jump.
|
||||
if ((ULONG_PTR)ct->pTarget <= dest
|
||||
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
|
||||
{
|
||||
if (jmpDest < dest)
|
||||
jmpDest = dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
jmp.address = dest;
|
||||
#else
|
||||
jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));
|
||||
#endif
|
||||
pCopySrc = &jmp;
|
||||
copySize = sizeof(jmp);
|
||||
|
||||
// Exit the function If it is not in the branch
|
||||
finished = (pOldInst >= jmpDest);
|
||||
}
|
||||
}
|
||||
else if ((hs.opcode & 0xF0) == 0x70
|
||||
|| (hs.opcode & 0xFC) == 0xE0
|
||||
|| (hs.opcode2 & 0xF0) == 0x80)
|
||||
{
|
||||
// Direct relative Jcc
|
||||
ULONG_PTR dest = pOldInst + hs.len;
|
||||
|
||||
if ((hs.opcode & 0xF0) == 0x70 // Jcc
|
||||
|| (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ
|
||||
dest += (INT8)hs.imm.imm8;
|
||||
else
|
||||
dest += (INT32)hs.imm.imm32;
|
||||
|
||||
// Simply copy an internal jump.
|
||||
if ((ULONG_PTR)ct->pTarget <= dest
|
||||
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
|
||||
{
|
||||
if (jmpDest < dest)
|
||||
jmpDest = dest;
|
||||
}
|
||||
else if ((hs.opcode & 0xFC) == 0xE0)
|
||||
{
|
||||
// LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Invert the condition in x64 mode to simplify the conditional jump logic.
|
||||
jcc.opcode = 0x71 ^ cond;
|
||||
jcc.address = dest;
|
||||
#else
|
||||
jcc.opcode1 = 0x80 | cond;
|
||||
jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));
|
||||
#endif
|
||||
pCopySrc = &jcc;
|
||||
copySize = sizeof(jcc);
|
||||
}
|
||||
}
|
||||
else if ((hs.opcode & 0xFE) == 0xC2)
|
||||
{
|
||||
// RET (C2 or C3)
|
||||
|
||||
// Complete the function if not in a branch.
|
||||
finished = (pOldInst >= jmpDest);
|
||||
}
|
||||
|
||||
// Can't alter the instruction length in a branch.
|
||||
if (pOldInst < jmpDest && copySize != hs.len)
|
||||
return FALSE;
|
||||
|
||||
// Trampoline function is too large.
|
||||
if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
|
||||
return FALSE;
|
||||
|
||||
// Trampoline function has too many instructions.
|
||||
if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
|
||||
return FALSE;
|
||||
|
||||
ct->oldIPs[ct->nIP] = oldPos;
|
||||
ct->newIPs[ct->nIP] = newPos;
|
||||
ct->nIP++;
|
||||
|
||||
// Avoid using memcpy to reduce the footprint.
|
||||
#ifndef _MSC_VER
|
||||
memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
|
||||
#else
|
||||
__movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
|
||||
#endif
|
||||
newPos += copySize;
|
||||
oldPos += hs.len;
|
||||
}
|
||||
while (!finished);
|
||||
|
||||
// Is there enough place for a long jump?
|
||||
if (oldPos < sizeof(JMP_REL)
|
||||
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
|
||||
{
|
||||
// Is there enough place for a short jump?
|
||||
if (oldPos < sizeof(JMP_REL_SHORT)
|
||||
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Can we place the long jump above the function?
|
||||
if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
|
||||
return FALSE;
|
||||
|
||||
if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
|
||||
return FALSE;
|
||||
|
||||
ct->patchAbove = TRUE;
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Create a relay function.
|
||||
jmp.address = (ULONG_PTR)ct->pDetour;
|
||||
|
||||
ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
|
||||
memcpy(ct->pRelay, &jmp, sizeof(jmp));
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// Structs for writing x86/x64 instructions.
|
||||
|
||||
// 8-bit relative jump.
|
||||
typedef struct _JMP_REL_SHORT
|
||||
{
|
||||
UINT8 opcode; // EB xx: JMP +2+xx
|
||||
UINT8 operand;
|
||||
} JMP_REL_SHORT, *PJMP_REL_SHORT;
|
||||
|
||||
// 32-bit direct relative jump/call.
|
||||
typedef struct _JMP_REL
|
||||
{
|
||||
UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
|
||||
UINT32 operand; // Relative destination address
|
||||
} JMP_REL, *PJMP_REL, CALL_REL;
|
||||
|
||||
// 64-bit indirect absolute jump.
|
||||
typedef struct _JMP_ABS
|
||||
{
|
||||
UINT8 opcode0; // FF25 00000000: JMP [+6]
|
||||
UINT8 opcode1;
|
||||
UINT32 dummy;
|
||||
UINT64 address; // Absolute destination address
|
||||
} JMP_ABS, *PJMP_ABS;
|
||||
|
||||
// 64-bit indirect absolute call.
|
||||
typedef struct _CALL_ABS
|
||||
{
|
||||
UINT8 opcode0; // FF15 00000002: CALL [+6]
|
||||
UINT8 opcode1;
|
||||
UINT32 dummy0;
|
||||
UINT8 dummy1; // EB 08: JMP +10
|
||||
UINT8 dummy2;
|
||||
UINT64 address; // Absolute destination address
|
||||
} CALL_ABS;
|
||||
|
||||
// 32-bit direct relative conditional jumps.
|
||||
typedef struct _JCC_REL
|
||||
{
|
||||
UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx
|
||||
UINT8 opcode1;
|
||||
UINT32 operand; // Relative destination address
|
||||
} JCC_REL;
|
||||
|
||||
// 64bit indirect absolute conditional jumps that x64 lacks.
|
||||
typedef struct _JCC_ABS
|
||||
{
|
||||
UINT8 opcode; // 7* 0E: J** +16
|
||||
UINT8 dummy0;
|
||||
UINT8 dummy1; // FF25 00000000: JMP [+6]
|
||||
UINT8 dummy2;
|
||||
UINT32 dummy3;
|
||||
UINT64 address; // Absolute destination address
|
||||
} JCC_ABS;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct _TRAMPOLINE
|
||||
{
|
||||
LPVOID pTarget; // [In] Address of the target function.
|
||||
LPVOID pDetour; // [In] Address of the detour function.
|
||||
LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
LPVOID pRelay; // [Out] Address of the relay function.
|
||||
#endif
|
||||
BOOL patchAbove; // [Out] Should use the hot patch area?
|
||||
UINT nIP; // [Out] Number of the instruction boundaries.
|
||||
UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function.
|
||||
UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function.
|
||||
} TRAMPOLINE, *PTRAMPOLINE;
|
||||
|
||||
BOOL CreateTrampolineFunction(PTRAMPOLINE ct);
|
Loading…
x
Reference in New Issue
Block a user