This commit is contained in:
HIllya51 2024-01-12 23:57:29 +08:00
parent 34e05da0fa
commit 75713f8322
32 changed files with 331 additions and 1003 deletions

View File

@ -293,7 +293,7 @@ class MAINUI() :
self.refresh_on_get_trans_signature=_showrawfunction_sig
_showrawfunction()
if currentsignature==self.currentsignature:
if currentsignature==self.currentsignature and globalconfig['showfanyi']:
self.translation_ui.displayres.emit(globalconfig['fanyi'][classname]['name'],globalconfig['fanyi'][classname]['color'],res,onlytrans)
if embedcallback:

View File

@ -1,7 +1,13 @@
baseobject=None
from traceback import print_exc
import io,sys
import io,sys,platform,os
isbit64= platform.architecture()[0]=='64bit'
DLL3264path=os.path.abspath('files/plugins/DLL'+('32','64')[isbit64])
def GetDllpath(_):
if isinstance(_,str):
return os.path.join(DLL3264path,_)
elif isinstance(_,(list,tuple)):
return os.path.join(DLL3264path,_[isbit64])
class debugoutput(io.IOBase):
def __init__(self,idx,file=sys.stdout) -> None:
super().__init__()

View File

@ -304,6 +304,7 @@ class hookselect(closeashidewindow):
self.allres=OrderedDict()
self.hidesearchhookbuttons()
def addnewhook(self,ss ,select,textthread):
hc,hn,tp=textthread
if len(self.save)==0:
if gobject.baseobject.textsource.allow_set_text_name:
self.ttCombomodelmodel.setHorizontalHeaderLabels(_TRL(['显示','类型','HOOK','文本']))
@ -354,8 +355,8 @@ class hookselect(closeashidewindow):
label.setStyleSheet("background-color: rgba(255, 255, 255, 0)")
checkbtn=QPushButton()
checkbtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
def _t():
_isusing=gobject.baseobject.textsource.checkisusingembed(textthread[0].tp.addr,textthread[0].tp.ctx,textthread[0].tp.ctx2)
def _t(tp):
_isusing=gobject.baseobject.textsource.checkisusingembed(tp.addr,tp.ctx,tp.ctx2)
if _isusing:
_text='取消内嵌翻译'
checkifnewgame(gobject.baseobject.textsource.pname)
@ -371,21 +372,21 @@ class hookselect(closeashidewindow):
_text="使用内嵌翻译"
checkbtn.setText(''+_TR(_text)+'')
return _isusing
_t()
def _c(_):
gobject.baseobject.textsource.useembed(textthread[0].tp.addr,textthread[0].tp.ctx,textthread[0].tp.ctx2,not _t())
_use=_t()
_t(tp)
def _c(hc,tp,_):
gobject.baseobject.textsource.useembed(tp.addr,tp.ctx,tp.ctx2,not _t(tp))
_use=_t(tp)
if _use:
savehook_new_data[gobject.baseobject.textsource.pname]['embedablehook'].append([textthread[0].hpcode,textthread[0].tp.addr,textthread[0].tp.ctx,textthread[0].tp.ctx2])
savehook_new_data[gobject.baseobject.textsource.pname]['embedablehook'].append([hc,tp.addr,tp.ctx,tp.ctx2])
else:
save=[]
for _ in savehook_new_data[gobject.baseobject.textsource.pname]['embedablehook']:
hc,ad,c1,c2=_
if(hc,ad,c1,c2)==(textthread[0].hpcode,textthread[0].tp.addr,textthread[0].tp.ctx,textthread[0].tp.ctx2):
if(hc,ad,c1,c2)==(hc,tp.addr,tp.ctx,tp.ctx2):
save.append(_)
for _ in save:
savehook_new_data[gobject.baseobject.textsource.pname]['embedablehook'].remove(_)
checkbtn.clicked.connect(_c)
checkbtn.clicked.connect(functools.partial(_c,hc,tp))
hlay.addWidget(checkbtn)
colidx=2+(gobject.baseobject.textsource.allow_set_text_name)
self.tttable.setIndexWidget(self.ttCombomodelmodel.index(rown,colidx),embedw)

View File

@ -28,7 +28,8 @@ def gethookgrid(self) :
[('文本缓冲区长度',5),(getspinbox(0,10000,globalconfig,'flushbuffersize',callback=lambda x:gobject.baseobject.textsource.setsettings()),3)],
[('过滤包含乱码的文本行',5),(getsimpleswitch(globalconfig,'filter_chaos_code'),1),(getcolorbutton(globalconfig,'',icon='fa.gear',constcolor="#FF69B4",callback=lambda:codeacceptdialog(self)),1)],
[],
[('区分人名和文本',5),getsimpleswitch(globalconfig,'allow_set_text_name')]
[('区分人名和文本',5),getsimpleswitch(globalconfig,'allow_set_text_name')],
[('使用YAPI注入',5),getsimpleswitch(globalconfig,'use_yapi')],
]

View File

@ -133,7 +133,7 @@ def setTabThree_lazy(self) :
[('显示日语注音',4),self.show_hira_switch,'',('注音颜色',4),getcolorbutton(globalconfig,'jiamingcolor',callback=lambda: selectcolor(self,globalconfig, "jiamingcolor", self.jiamingcolor_b),name='jiamingcolor_b',parent=self),'',('注音字体缩放',3),(getspinbox(0.05,1,globalconfig,'kanarate',double=True,step=0.05,dec=2),2)],
[('语法加亮',4 ),self.show_fenciswitch,'',
('词性颜色(需要Mecab)',4), getcolorbutton(globalconfig,'',callback=lambda : multicolorset(self),icon='fa.gear',constcolor="#FF69B4") ,],
[("显示翻译器名称",4),(getsimpleswitch(globalconfig ,'showfanyisource'),1)],
[("显示翻译器名称",4),(getsimpleswitch(globalconfig ,'showfanyisource'),1),'',("显示翻译",4),(getsimpleswitch(globalconfig ,'showfanyi'),1)],
[('最长显示字数',4),(getspinbox(0,1000000,globalconfig,'maxoriginlength'),2)],
[],

View File

@ -1,7 +1,7 @@
import platform,os
import gobject,os
from ctypes import CDLL,c_void_p,c_int,c_char_p,c_long,cast,CFUNCTYPE,c_size_t,Structure,pointer,create_string_buffer,memmove,POINTER,c_char,c_int64,c_uint
curlpath=os.path.abspath(os.path.join('./files/plugins',['./libcurl-x64.dll','./libcurl.dll'][platform.architecture()[0]=='32bit']))
libcurl=CDLL(curlpath)
libcurl=CDLL(os.path.join(gobject.DLL3264path,('./libcurl.dll','./libcurl-x64.dll')[gobject.isbit64]))
CURL = c_void_p
CURLSH=c_void_p
class curl_slist(Structure):

View File

@ -1,11 +1,8 @@
from ctypes import CDLL,c_size_t,c_void_p,POINTER,pointer,create_string_buffer
import os,platform
dllpath=os.path.abspath(os.path.join('./files/plugins/brotli',['./x64/brotlicommon.dll','./x86/brotlicommon.dll'][platform.architecture()[0]=='32bit']))
_brotli=CDLL(dllpath)
dllpath=os.path.abspath(os.path.join('./files/plugins/brotli',['./x64/brotlidec.dll','./x86/brotlidec.dll'][platform.architecture()[0]=='32bit']))
_brotli=CDLL(dllpath)
import os,gobject
_brotli=CDLL(gobject.GetDllpath('brotlicommon.dll'))
_brotli=CDLL(gobject.GetDllpath('brotlidec.dll'))
BrotliDecoderDecompress=_brotli.BrotliDecoderDecompress
BrotliDecoderDecompress.argtypes=c_size_t,c_void_p,POINTER(c_size_t),c_void_p
def decompress(data):

View File

@ -7,15 +7,10 @@ import base64
from ocrengines.baseocrclass import baseocr
from ctypes import CDLL,c_char_p ,create_string_buffer,c_uint32,POINTER,c_int32
import os
import platform
import gobject
class ocrwrapper:
def __init__(self) -> None:
if platform.architecture()[0]=='64bit':
bit='64'
else:
bit='32'
self.dll=CDLL(os.path.abspath('./files/plugins/ocr{}.dll'.format(bit)) )
def __init__(self) -> None:
self.dll=CDLL(gobject.GetDllpath(('ocr32.dll','ocr64.dll')))
def _OcrInit(self,szDetModel, szRecModel, szKeyPath,szClsModel='', nThreads=4):
_OcrInit=self.dll.OcrInit

View File

@ -1,203 +0,0 @@
STRING = 12
MESSAGE_SIZE = 500
PIPE_BUFFER_SIZE = 50000
SHIFT_JIS = 932
MAX_MODULE_SIZE = 120
PATTERN_SIZE = 30
HOOK_NAME_SIZE = 60
FIXED_SPLIT_VALUE = 0x10001
import ctypes
from ctypes import Structure,c_int,c_char,c_uint64,c_uint,sizeof,c_wchar,c_short,c_uint32,c_bool,c_ubyte
class HostNotificationType(c_int):
pass
HOST_NOTIFICATION_TEXT=0
HOST_NOTIFICATION_NEWHOOK=1
HOST_NOTIFICATION_FOUND_HOOK=2
HOST_NOTIFICATION_RMVHOOK=3
HOST_NOTIFICATION_INSERTHOOK=4
class HostCommandType(c_uint):
pass
HOST_COMMAND_NEW_HOOK=0
HOST_COMMAND_REMOVE_HOOK=1
HOST_COMMAND_FIND_HOOK=2
HOST_COMMAND_MODIFY_HOOK=3
HOST_COMMAND_HIJACK_PROCESS=4
HOST_COMMAND_DETACH=5
HOST_COMMAND_NEW_HOOK_NAIVE=6
class ThreadParam(Structure):
_fields_=[
('processId',c_uint),
('addr',c_uint64),
('ctx',c_uint64),
('ctx2',c_uint64)
]
def __hash__(self):
return hash((self.processId, self.addr,self.ctx,self.ctx2))
def __eq__(self, __value ):
return self.__hash__()==__value.__hash__()
class HookParam(Structure):
_fields_=[
('address',c_uint64),
('offset',c_int),
('index',c_int),
('split',c_int),
('split_index',c_int),
('null_length',c_int),
('module',c_wchar*MAX_MODULE_SIZE),
('function',c_char*MAX_MODULE_SIZE),
('type',c_uint),
('codepage', c_uint),
('length_offset',c_short),
('padding',c_uint64), #uintptr_t
('user_value',c_uint),
('text_fun',c_uint64),
('filter_fun',c_uint64),
('hook_fun',c_uint64),
('length_fun',c_uint64), #函数指针
('_1',c_uint64),
('_2',c_uint64),
('_3',c_uint64),
('_4',c_uint64),
('name',c_char*HOOK_NAME_SIZE)
]
class TextHook(Structure):
_fields_=[
('hp',HookParam),
('address',c_uint64), #union{uint64 && void*}
('useCount',c_uint),
('readerThread',c_uint64), #HANLDE ->void*
('readerEvent',c_uint64),
('err',c_bool),
('trampoline',c_ubyte*140),
('local_buffer',c_uint64)
]
MAX_HOOK=2500
class SearchParam(Structure):
_fields_=[
('pattern',c_char*30),
('address_method',c_int),
('search_method',c_int),
('length',c_int),
('offset',c_int),
('searchTime',c_int),
('maxRecords',c_int),
('codepage',c_int),
('padding',c_uint64),
('minAddress',c_uint64),
('maxAddress',c_uint64),
('boundaryModule',c_wchar*120),
('exportModule',c_wchar*120),
('text',c_wchar*30)
]
class DetachCmd(Structure):
_fields_=[
('command',HostCommandType),
]
def __init__(self) -> None:
self.command=HOST_COMMAND_DETACH
class RemoveHookCmd(Structure):
_fields_=[
('command',HostCommandType),
('address',c_uint64)
]
def __init__(self, address) -> None:
self.command=HOST_COMMAND_REMOVE_HOOK
self.address=address
class InsertHookCmd(Structure):
_fields_=[
('command',HostCommandType),
('hp',HookParam)
]
def __init__(self, hp) -> None:
self.command=HOST_COMMAND_NEW_HOOK
self.hp=hp
class InsertHookCodeNaive(Structure):
_fields_=[
('command',HostCommandType),
('hcode',c_wchar*500)
]
def __init__(self, hp) -> None:
self.command=HOST_COMMAND_NEW_HOOK_NAIVE
self.hcode=hp
class FindHookCmd(Structure):
_fields_=[
('command',HostCommandType),
('sp',SearchParam)
]
def __init__(self, sp) -> None:
self.command=HOST_COMMAND_FIND_HOOK
self.sp=sp
class RemoveHookCmd(Structure):
_fields_=[
('command',HostCommandType),
('address',c_uint64)
]
def __init__(self, address) -> None:
self.command=HOST_COMMAND_REMOVE_HOOK
self.address=address
class hookfoundtext(Structure):
_fields_=[('text',c_wchar*MESSAGE_SIZE)]
class HookFoundNotif(Structure):
_fields_=[
('command',HostNotificationType),
('hp',HookParam),
('hcode',c_wchar*500),
('text',hookfoundtext)
]
class ConsoleOutputNotif(Structure):
_fields_=[
('command',HostNotificationType),
('message',c_char*MESSAGE_SIZE)
]
class HookRemovedNotif(Structure):
_fields_=[
('command',HostNotificationType),
('address',c_uint64)
]
class HookInsertingNotif(Structure):
_fields_=[
('command',HostNotificationType),
('addr',c_uint64),
]
SHAREDMEMDPREFIX='LUNA_VNR_SECTION_'
HOOKCODEGET='LUNA_HOOKCODE_'
HOOK_PIPE_NAME="\\\\.\\pipe\\LUNA_HOOK"
HOST_PIPE_NAME="\\\\.\\pipe\\LUNA_HOST"
PIPE_AVAILABLE_EVENT = "LUNA_PIPE_AVAILABLE"
class Hookcodeshared(Structure):
_fields_=[('code',c_wchar*500)]
class EmbedSharedMem(ctypes.Structure):
_fields_=[
('using',ctypes.c_uint64*10),
('addr',ctypes.c_uint64*10),
('ctx1',ctypes.c_uint64*10),
('ctx2',ctypes.c_uint64*10),
('waittime',ctypes.c_uint32),
('spaceadjustpolicy',ctypes.c_uint32),
('keeprawtext',ctypes.c_uint32),
('hash',ctypes.c_uint64),
('text',ctypes.c_wchar*1000),
('fontCharSetEnabled',ctypes.c_bool),
('fontCharSet',ctypes.c_uint8),
('fontFamily',ctypes.c_wchar*100),
]
EMBED_SHARED_MEM="EMBED_SHARED_MEM"
LUNA_NOTIFY="LUNA_NOTIFY.%s.%s"
ITH_HOOKMAN_MUTEX_="LUNA_VNR_HOOKMAN_"

View File

@ -1,265 +0,0 @@
import textsource.hook.define as define
import windows
from traceback import print_exc
#import define
import re,copy
USING_STRING = 0x1 # type(data) is char * or wchar_t * and has length
USING_UNICODE = 0x2 # type(data) is wchar_t or wchar_t*
BIG_ENDIAN = 0x4 # type(data) is char
DATA_INDIRECT = 0x8
USING_SPLIT = 0x10 # use ctx2 or not
SPLIT_INDIRECT = 0x20
MODULE_OFFSET = 0x40 # address is relative to module
FUNCTION_OFFSET = 0x80 # address is relative to function
USING_UTF8 = 0x100
NO_CONTEXT = 0x200
HOOK_EMPTY = 0x400
FIXING_SPLIT = 0x800
DIRECT_READ = 0x1000 # /R read code instead of classic / H hook code
FULL_STRING = 0x2000
HEX_DUMP = 0x4000
HOOK_ENGINE = 0x8000
HOOK_ADDITIONAL = 0x10000
KNOWN_UNSTABLE = 0x20000
def ConsumeHexInt(HCode):
match = re.match(r'^([+-]?[0-9a-fA-F]+)', HCode)
if match:
value = int(match.group(1), 16)
HCode = HCode[match.end():]
return HCode,value
else:
return HCode,0
def Hex(st):
return hex(st).replace('0x','').upper()
def ParseRCode(RCode) :
hp=define.HookParam()
hp.type |= DIRECT_READ
if RCode[0]=='S':
pass
elif RCode[0] == 'Q':
hp.type |= USING_UNICODE
elif RCode[0] == 'V':
hp.type |= USING_UTF8
elif RCode[0] == 'M':
hp.type |= USING_UNICODE | HEX_DUMP
else:
return None
RCode = RCode[1:]
# [null_length<]
match = re.match(r"^([0-9]+)<", RCode)
if match:
hp.null_length = int(match.group(1))
RCode = RCode[len(match.group(0)):]
# [codepage#]
match = re.match(r"^([0-9]+)#", RCode)
if match:
hp.codepage = int(match.group(1))
RCode = RCode[len(match.group(0)):]
# @addr
match = re.match(r"@([0-9a-fA-F]+)", RCode)
if not match:
return None
hp.address = int(match.group(1), 16)
return hp
def ParseHCode(HCode):
hp=define.HookParam()
if HCode[0] == 'A':
hp.type |= BIG_ENDIAN
hp.length_offset = 1
elif HCode[0] == 'B':
hp.length_offset = 1
elif HCode[0] == 'W':
hp.type |= USING_UNICODE
hp.length_offset = 1
elif HCode[0] == 'H':
hp.type |= USING_UNICODE | HEX_DUMP
hp.length_offset = 1
elif HCode[0] == 'S':
hp.type |= USING_STRING
elif HCode[0] == 'Q':
hp.type |= USING_STRING | USING_UNICODE
elif HCode[0] == 'V':
hp.type |= USING_STRING | USING_UTF8
elif HCode[0] == 'M':
hp.type |= USING_STRING | USING_UNICODE | HEX_DUMP
else:
return None
HCode = HCode[1:]
if hp.type & USING_STRING:
if HCode[0] == 'F':
hp.type |= FULL_STRING
HCode = HCode[1:]
# [null_length<]
match = re.match(r'^([0-9]+)<', HCode)
if match:
hp.null_length = int(match.group(1))
HCode = HCode[match.end():]
# [N]
if HCode[0] == 'N':
hp.type |= NO_CONTEXT
HCode = HCode[1:]
# [codepage#]
match = re.match(r'^([0-9]+)#', HCode)
if match:
hp.codepage = int(match.group(1))
HCode = HCode[match.end():]
# [padding+]
match = re.match(r'^([0-9a-fA-F]+)\+', HCode)
if match:
hp.padding = int(match.group(1), 16)
HCode = HCode[match.end():]
HCode,hp.offset=ConsumeHexInt(HCode)
# [*deref_offset1]
if HCode[0] == '*':
hp.type |= DATA_INDIRECT
HCode = HCode[1:]
HCode,hp.index=ConsumeHexInt(HCode)
# [:split_offset[*deref_offset2]]
if HCode[0] == ':':
hp.type |= USING_SPLIT
HCode = HCode[1:]
HCode,hp.split=ConsumeHexInt(HCode)
if HCode[0] == '*':
hp.type |= SPLIT_INDIRECT
HCode = HCode[1:]
HCode,hp.split_index=ConsumeHexInt(HCode)
# @addr[:module[:func]]
match = re.match(r'^@([0-9a-fA-F]+)(:.+?)?(:.+)?$', HCode)
if match is None:
return None
hp.address = int(match.group(1), 16)
if match.group(2):
hp.type |= MODULE_OFFSET
hp.module = match.group(2)[1:]
if match.group(3):
hp.type |= FUNCTION_OFFSET
hp.function =bytes(match.group(3)[1:],encoding='ascii')
# ITH has registers offset by 4 vs AGTH: need this to correct
if hp.offset < 0:
hp.offset -= 4
if hp.split < 0:
hp.split -= 4
return hp
def Parse(code):
code=code.strip().replace('\r','').replace('\n','').replace('\t','')
if(code[0]=='/'):code=code[1:]
if('/' in code):code=code.split('/')[0]
if(code[0]=='R'):
hp=ParseRCode(code[1:])
elif(code[0]=='H'):
hp=ParseHCode(code[1:])
else:
hp=None
return hp
def GenerateRCode(hp):
RCode = 'R'
if hp.type & USING_UNICODE:
if hp.type & HEX_DUMP:
RCode += 'M'
else:
RCode += 'Q'
if hp.null_length != 0:
RCode += str(hp.null_length) + '<'
else:
RCode += 'S'
if hp.null_length != 0:
RCode += str(hp.null_length) + '<'
if hp.codepage != 0:
RCode += str(hp.codepage) + '#'
RCode += '@' + Hex(hp.address)
return RCode
def GenerateHCode(hp,processId):
HCode = "H"
if hp.type & USING_UNICODE:
if hp.type & HEX_DUMP:
if hp.type & USING_STRING:
HCode += "M"
else:
HCode += "H"
else:
if hp.type & USING_STRING:
HCode += "Q"
else:
HCode += "W"
else:
if hp.type & USING_STRING:
HCode += "S"
elif hp.type & BIG_ENDIAN:
HCode += "A"
else:
HCode += "B"
if hp.type & FULL_STRING:
HCode += "F"
if hp.null_length != 0:
HCode += str(hp.null_length) + "<"
if hp.type & NO_CONTEXT:
HCode += "N"
if hp.text_fun or hp.filter_fun or hp.hook_fun or hp.length_fun:
HCode += "X" # no AGTH equivalent
if hp.codepage != 0 and not (hp.type & USING_UNICODE):
HCode += str(hp.codepage) + "#"
if hp.padding:
HCode += Hex(hp.padding) + "+"
if hp.offset < 0:
hp.offset += 4
if hp.split < 0:
hp.split += 4
HCode += Hex(hp.offset)
if hp.type & DATA_INDIRECT:
HCode += "*" + Hex(hp.index)
if hp.type & USING_SPLIT:
HCode += ":" + Hex(hp.split)
if hp.type & SPLIT_INDIRECT:
HCode += "*" + Hex(hp.split_index)
# Attempt to make the address relative
try:
if processId and not (hp.type & MODULE_OFFSET):
process =windows.AutoHandle(windows.OpenProcess(windows.PROCESS_VM_READ | windows.PROCESS_QUERY_INFORMATION, False, processId))
if process:
info=windows.VirtualQueryEx(process,hp.address)
if info.AllocationBase:
module_name =windows.GetModuleFileNameEx(process, info.AllocationBase)
if module_name:
hp.address -= info.AllocationBase
hp.type |= MODULE_OFFSET
hp.module = module_name[module_name.rfind('\\')+1:][:120]
except:
pass
#print_exc()
HCode += "@" + Hex(hp.address)
if hp.type & MODULE_OFFSET:
HCode += ":" + hp.module
if hp.type & FUNCTION_OFFSET:
HCode += ":" + hp.function.decode('ascii')
return HCode
def Generate(_hp,process_id):
hp=copy.copy(_hp)
if hp.type&DIRECT_READ :
code=GenerateRCode(hp)
else:
code=GenerateHCode(hp,process_id)
return code
if __name__=='__main__':
# print(Parse("/HQN936#1+-c*C:C*1C@4AA:gdi.dll:GetTextOutA",hp))
# print(Parse("/HQN936#-c*C:C*1C@4AA:gdi.dll:GetTextOutA /KF",hp))
# print(Parse("HB4@0" ,hp)),
# print(Parse("/RS65001#@44",hp)),
# print(Parse("HQ@4",hp,))
print(Parse('/HS8:-14@76D85270'))
# print(Parse("/RW@44",hp)),
# print(Parse("/HWG@33",hp))

View File

@ -1,303 +0,0 @@
import threading
import textsource.hook.define as define
import ctypes,time
from ctypes import Structure,c_int,c_char,sizeof,cast,POINTER
from myutils.wrapper import threader
import sys
import os ,subprocess
from myutils.config import globalconfig
import windows
from myutils.hwnd import testprivilege
import ctypes
import textsource.hook.hookcode as hookcode
class ProcessRecord():
def __init__(self,pipe,processId) -> None:
self.pipe=pipe
self.processId=processId
buff=define.MAX_HOOK*define.TextHook
HOOK_SECTION_SIZE=sizeof(buff)
self.OnHookFound=0
fmap1=windows.OpenFileMapping(windows.FILE_MAP_READ,False,define.SHAREDMEMDPREFIX+str(processId))
address1=windows.MapViewOfFile(fmap1, windows.FILE_MAP_READ, HOOK_SECTION_SIZE)
fmap2=windows.OpenFileMapping(windows.FILE_MAP_READ,False,define.HOOKCODEGET+str(processId))
address2=windows.MapViewOfFile(fmap2, windows.FILE_MAP_READ, sizeof(define.MAX_HOOK*define.Hookcodeshared))
self.sharedtexthook=cast(address1,POINTER(buff))
self.sharedhookcode=cast(address2,POINTER(define.MAX_HOOK*define.Hookcodeshared))
def GetHook(self,addr):
for i,_hook in enumerate(self.sharedtexthook.contents):
if(_hook.address==addr):
code=self.sharedhookcode.contents[i].code
return _hook,code
return None,None
def Send(self,struct):
windows.WriteFile(self.pipe,bytes(struct))
#calls
def Detach(self):
self.Send(define.DetachCmd())
def RemoveHook(self,address):
self.Send((define.RemoveHookCmd(address)))
def InsertHookCode(self,string):
if len(string) and string[0]=='E':
self.Send(define.InsertHookCodeNaive(string))
else:
hp=hookcode.Parse(string)
print(hp)
if hp:
self.Send(define.InsertHookCmd(hp))
return True
else:
return False
def FindHooks(self,sp,OnHookFound):
self.OnHookFound=OnHookFound
self.Send(define.FindHookCmd(sp))
self.OnHookFound=OnHookFound
def RemoveHook(self,addr):
self.Send(define.RemoveHookCmd(addr));
class TextThread():
def __init__(self,rpc,tp,_,host) -> None:
(texthook,hcode)=_
hp=texthook.hp
self.tp=tp
self.rpc=rpc
self.hp=hp
self.hpcode=hcode#hookcode.Generate(hp,tp.processId)
self.host=host
self.buffer=''
self.lasttime=0
self.lock=threading.Lock()
self.leadbyte=0
self.saverepeat=''
def Push(self,buff):
self.lock.acquire()
buffer=self.parsebuff(buff)
if self.rpc.setting.timeout==0 and self.hp.type&hookcode.FULL_STRING:
self.rpc.Output(self,buffer)
elif not( globalconfig['direct_filterrepeat']and (len(buffer)>=3) and (buffer in self.saverepeat)):
self.buffer+=buffer
self.lasttime=time.time()
if len(self.buffer):
self.saverepeat=self.buffer
if len(self.buffer)>=self.host.setting.flushbuffersize:
_=self.buffer
self.buffer=''
self.rpc.Output(self,_)
self.lock.release()
def parsebuff(self,buff):
hp=self.hp
if hp.codepage==0:
cp=self.host.setting.defaultcodepag
else:
cp=hp.codepage
if len(buff)==1:
if self.leadbyte:
buff=self.leadbyte+buff
self.leadbyte=0
else:
if(windows.IsDBCSLeadByteEx(cp,buff[0])):
self.leadbyte=buff
return ''
if (hp.type &hookcode.HEX_DUMP) :
_ret=buff.hex()
elif hp.type& hookcode.USING_UNICODE:
try:
_ret=buff.decode('utf-16',errors='ignore')
except:
return ''
else:
if hp.codepage==0:
cp=self.host.setting.defaultcodepag
else:
cp=hp.codepage
_ret=windows.MultiByteToWideChar(buff,len(buff),cp)
if _ret is None:
_ret=''
if hp.type&hookcode.FULL_STRING:
_ret+='\n'
return _ret
class RPCSettings:
def __init__(self) -> None:
self.timeout=100
self.defaultcodepag=932
self.flushbuffersize=3000
class RPC():
def callbacks(self,OnConnect,OnDisconnect,OnCreate,OnDestroy,Output,Console,EmbedCall,HookInsert):
self.OnDisconnect=threader(OnDisconnect)
self.OnConnect=threader(OnConnect)
self.OnCreate=(OnCreate) #有并发问题会插入Embed的text两次
self.OnDestroy=threader(OnDestroy)
self.Output=threader(Output)
self.Console=threader(Console)
self.EmbedCall=threader(EmbedCall)
self.HookInsert=threader(HookInsert)
def toint(self,byte4):
return c_int.from_buffer_copy(byte4).value
def end(self):
for _ in self.hookPipes:
windows.CancelIo(_)
def __init__(self) -> None:
self.ProcessRecord={}
self.textthreadslock=threading.Lock()
self.textthreads={}
self.hookPipes=[]
self.setting=RPCSettings()
threading.Thread(target=self.outputthread).start()
def outputthread(self):
while True:
time.sleep(0.001)
timenow=time.time()
self.textthreadslock.acquire()
for _,textthread in self.textthreads.items():
textthread.lock.acquire()
if len(textthread.buffer)>0 and (timenow-textthread.lasttime>self.setting.timeout/1000):
buff=textthread.buffer
textthread.buffer=''
self.Output(textthread,buff)
textthread.lasttime=timenow
textthread.lock.release()
self.textthreadslock.release()
def start(self,pid):
hookPipe = windows.CreateNamedPipe(define.HOOK_PIPE_NAME+str(pid),
windows.PIPE_ACCESS_INBOUND,
windows.PIPE_TYPE_MESSAGE | windows.PIPE_READMODE_MESSAGE | windows.PIPE_WAIT,
windows.PIPE_UNLIMITED_INSTANCES,
0,
0,
0)
hostPipe = windows.CreateNamedPipe(define.HOST_PIPE_NAME+str(pid),
windows.PIPE_ACCESS_OUTBOUND,
windows.PIPE_TYPE_MESSAGE | windows.PIPE_READMODE_MESSAGE | windows.PIPE_WAIT,
windows.PIPE_UNLIMITED_INSTANCES,
0,
0,
0 )
pipeAvailableEvent = windows.CreateEvent(False, False, define.PIPE_AVAILABLE_EVENT+str(pid))
windows.SetEvent(pipeAvailableEvent)
self.hookPipes.append(hookPipe)
def _():
windows.ConnectNamedPipe(hookPipe, None)
windows.CloseHandle(pipeAvailableEvent)
processId = self.toint(windows.ReadFile(hookPipe, 4,None) )
self.ProcessRecord[processId]=ProcessRecord(hostPipe,processId)
self.OnConnect(processId)
while True:
data=windows.ReadFile(hookPipe,50000,None)
if len(data)==0 :break
if len(data)==50000:continue
self.OnMessage(data,processId)
self.ProcessRecord.pop(processId)
windows.CloseHandle(hookPipe)
windows.CloseHandle(hostPipe)
self.removethreads(processId)
self.OnDisconnect((processId))
threading.Thread(target=_,daemon=True).start()
def removethreads(self,pid,addr=None):
self.textthreadslock.acquire()
toremove=[]
for textthread in self.textthreads:
if textthread.processId==pid:
if addr:
if textthread.addr==addr:
toremove.append(textthread)
else:
toremove.append(textthread)
for _ in toremove:
self.textthreads.pop(_)
self.OnDestroy(_)
self.textthreadslock.release()
def OnMessage(self,data,processId):
cmd=self.toint(data[:4])
if(cmd==define. HOST_NOTIFICATION_TEXT):
try:
message=define.ConsoleOutputNotif.from_buffer_copy(data).message.decode('utf8')
except:
message="ErrorDecodeMessage"
self.Console(message)
elif(cmd==define.HOST_NOTIFICATION_FOUND_HOOK):
_HookFoundNotif=define.HookFoundNotif
_HookFoundNotif=_HookFoundNotif.from_buffer_copy(data)
text=_HookFoundNotif.text.text
#print(_HookFoundNotif.hcode,hookcode.Generate(_HookFoundNotif.hp,processId))
hp=hookcode.Parse(_HookFoundNotif.hcode)
if len(text)>12:
self.ProcessRecord[processId].OnHookFound(hookcode.Generate(hp,processId),text)
hp.type&=~hookcode.USING_UNICODE
codepages=[hp.codepage]
if hp.codepage!=65001:
codepages+=[65001]
for codepage in codepages:
try:
hp.codepage=codepage
text=windows.MultiByteToWideChar(_HookFoundNotif.text.text,sizeof(define.hookfoundtext),hp.codepage)
if text is not None and len(text)>12:
self.ProcessRecord[processId].OnHookFound(hookcode.Generate(hp,processId),text)
except:pass
elif(cmd==define.HOST_NOTIFICATION_RMVHOOK):
self.removethreads(processId,define.HookRemovedNotif.from_buffer_copy(data).address)
elif(cmd==define.HOST_NOTIFICATION_INSERTHOOK):
addr=define.HookInsertingNotif.from_buffer_copy(data).addr
_,hcode=self.ProcessRecord[processId].GetHook(addr)
self.HookInsert(addr,hcode)
else:
tp=define.ThreadParam.from_buffer_copy(data)
if tp not in self.textthreads:
self.textthreadslock.acquire()
self.textthreads[tp]=TextThread(self,tp,self.ProcessRecord[tp.processId].GetHook(tp.addr),self)
self.OnCreate(self.textthreads[tp])
self.textthreadslock.release()
if self.textthreads[tp].hpcode[0]=='E':
#self.Output(self.textthreads[tp],self.textthreads[tp].parsebuff(data[sizeof(tp):]))
self.EmbedCall(self.textthreads[tp].parsebuff(data[sizeof(tp):]),self.textthreads[tp])
self.textthreads[tp].Push(data[sizeof(tp):])
#
def Attach(self,pids,arch):
injecter=os.path.abspath('./files/plugins/shareddllproxy{}.exe'.format(arch))
dll=os.path.abspath('./files/plugins/LunaHook/LunaHook{}.dll'.format(arch))
print(injecter,os.path.exists(injecter))
print(dll,os.path.exists(dll))
#subprocess.Popen('"{}" dllinject {} "{}"'.format(injecter,pid,dll))
pid=' '.join([str(_) for _ in pids])
if any(map(testprivilege,pids))==False:
windows.ShellExecute(0,'runas',injecter,'dllinject {} "{}"'.format(pid,dll),None,windows.SW_HIDE)
else:
ret=subprocess.run('"{}" dllinject {} "{}"'.format(injecter,pid,dll)).returncode
if(ret==0):
windows.ShellExecute(0,'runas',injecter,'dllinject {} "{}"'.format(pid,dll),None,windows.SW_HIDE)
@threader
def InsertHookCode(self,pid,hookcode):
if pid in self.ProcessRecord:
self.ProcessRecord[pid].InsertHookCode(hookcode)
@threader
def FindHooks(self,pid,sp,onfound):
if pid in self.ProcessRecord:
self.ProcessRecord[pid].FindHooks(sp,onfound)
@threader
def Detach(self,pid):
if pid in self.ProcessRecord:
self.ProcessRecord[pid].Detach()
@threader
def RemoveHook(self,pid,addr):
if pid in self.ProcessRecord:
self.ProcessRecord[pid].RemoveHook(addr)

View File

@ -4,17 +4,67 @@ import re ,os
import time ,gobject
from collections import OrderedDict
import ctypes,functools
import windows
import textsource.hook.define as define
import windows,subprocess
from myutils.config import globalconfig ,savehook_new_data ,_TR,static_data
from textsource.textsourcebase import basetext
from myutils.utils import checkchaos
from textsource.hook.host import RPC
from myutils.utils import checkchaos
from myutils.hwnd import testprivilege
from myutils.wrapper import threader
from ctypes import CDLL,c_bool,POINTER,Structure,c_int,pointer,c_wchar_p,c_uint64,sizeof,c_void_p,cast,c_wchar,c_uint32,c_uint8,c_uint,c_char,c_short
from ctypes.wintypes import DWORD,LPCWSTR,HANDLE
from gui.usefulwidget import getQMessageBox
MAX_MODULE_SIZE = 120
HOOK_NAME_SIZE = 60
HOOKCODE_LEN=500
class ThreadParam(Structure):
_fields_=[
('processId',c_uint),
('addr',c_uint64),
('ctx',c_uint64),
('ctx2',c_uint64)
]
def __hash__(self):
return hash((self.processId, self.addr,self.ctx,self.ctx2))
def __eq__(self, __value ):
return self.__hash__()==__value.__hash__()
class SearchParam(Structure):
_fields_=[
('pattern',c_char*30),
('address_method',c_int),
('search_method',c_int),
('length',c_int),
('offset',c_int),
('searchTime',c_int),
('maxRecords',c_int),
('codepage',c_int),
('padding',c_uint64),
('minAddress',c_uint64),
('maxAddress',c_uint64),
('boundaryModule',c_wchar*120),
('exportModule',c_wchar*120),
('text',c_wchar*30),
('_1',c_uint64)
]
class Message(Structure):
_fields_=[
('read',c_bool),
('type',c_int),
('pid',DWORD),
('hn',c_char*HOOK_NAME_SIZE),
('hc',c_wchar*HOOKCODE_LEN),
('tp',ThreadParam),
('stringptr',c_void_p),
('addr',c_uint64)
]
class simplehooks(Structure):
_fields_=[
('hookcode',c_wchar*500),
('text',c_void_p)
]
class texthook(basetext ):
def __init__(self,pids,hwnd,pname ,autostarthookcode=None,needinserthookcode=None) :
print(pids,hwnd,pname ,autostarthookcode,needinserthookcode)
self.RPC=RPC()
if autostarthookcode is None:
autostarthookcode=[]
if needinserthookcode is None:
@ -43,84 +93,143 @@ class texthook(basetext ):
self.isremoveuseless=savehook_new_data[self.pname]["removeuseless"] and len(self.autostarthookcode)
self.needinserthookcode=needinserthookcode
self.removedaddress=[]
self.HookCode=None
self.sharedcell=None
self.RPC.callbacks(
lambda pid:time.sleep(savehook_new_data[self.pname]['inserthooktimeout']/1000) or [self.RPC.InsertHookCode(pid,hookcode) for hookcode in needinserthookcode]+[self.createembedsharedmem(pid),self.showgamename()],
lambda pid: print(pid,"disconenct"),
self.onnewhook,
self.onremovehook,
self.handle_output,
gobject.baseobject.hookselectdialog.sysmessagesignal.emit,
self.getembedtext,
self.newhookinsert
)
self.setsettings()
gobject.baseobject.hookselectdialog.changeprocessclearsignal.emit()
if len(autostarthookcode)==0 and len(savehook_new_data[self.pname]['embedablehook'])==0:
gobject.baseobject.hookselectdialog.realshowhide.emit(True)
threading.Thread(target=self.delaycollectallselectedoutput).start()
_pids=[]
for pid in self.pids:
if self.testalready(pid)==False:
self.RPC.start(pid)
_pids.append(pid)
if len(_pids):
self.RPC.Attach(_pids,'64' if self.is64bit else '32')
super(texthook,self).__init__(*self.checkmd5prefix(pname))
def testalready(self,pid):
_mutext=windows.AutoHandle(windows.CreateMutex(False,define.ITH_HOOKMAN_MUTEX_+str(pid)))
err=windows.GetLastError()
exists= err==windows.ERROR_ALREADY_EXISTS
return exists
self.declare()
self.start()
def declare(self):
LunaHost=CDLL(gobject.GetDllpath(('LunaHost32.dll','LunaHost64.dll')))
self.Luna_Settings=LunaHost.Luna_Settings
self.Luna_Settings.argtypes=c_int,c_bool,c_int,c_int
self.Luna_Start=LunaHost.Luna_Start
self.Luna_Start.argtypes=POINTER(HANDLE),
self.Luna_Inject=LunaHost.Luna_Inject
self.Luna_Inject.argtypes=DWORD,LPCWSTR
self.Luna_CreatePipeAndCheck=LunaHost.Luna_CreatePipeAndCheck
self.Luna_CreatePipeAndCheck.argtypes=DWORD,
self.Luna_CreatePipeAndCheck.restype=c_bool
self.Luna_InsertHookCode=LunaHost.Luna_InsertHookCode
self.Luna_InsertHookCode.argtypes=DWORD,LPCWSTR
self.Luna_InsertHookCode.restype=c_bool
self.Luna_RemoveHook=LunaHost.Luna_RemoveHook
self.Luna_RemoveHook.argtypes=DWORD,c_uint64
self.Luna_Detach=LunaHost.Luna_Detach
self.Luna_Detach.argtypes=DWORD,
self.Luna_cfree=LunaHost.Luna_cfree
self.Luna_cfree.argtypes=c_void_p,
self.Luna_FindHooks=LunaHost.Luna_FindHooks
self.Luna_FindHooks.argtypes=DWORD,SearchParam,POINTER(HANDLE),POINTER(POINTER(c_int))
self.Luna_FindHooks_waiting=LunaHost.Luna_FindHooks_waiting
self.Luna_FindHooks_waiting.argtypes=POINTER(c_int),
self.Luna_EmbedSettings=LunaHost.Luna_EmbedSettings
self.Luna_EmbedSettings.argtypes=DWORD,c_uint32,c_uint8,c_bool,c_wchar_p,c_uint32,c_uint32
self.Luna_checkisusingembed=LunaHost.Luna_checkisusingembed
self.Luna_checkisusingembed.argtypes=DWORD,c_uint64,c_uint64,c_uint64
self.Luna_checkisusingembed.restype=c_bool
self.Luna_useembed=LunaHost.Luna_useembed
self.Luna_useembed.argtypes=DWORD,c_uint64,c_uint64,c_uint64,c_bool
self.Luna_embedcallback=LunaHost.Luna_embedcallback
self.Luna_embedcallback.argtypes=DWORD,LPCWSTR,LPCWSTR
def start(self):
self.hRead=HANDLE()
self.Luna_Start(pointer(self.hRead) )
self.setsettings()
injectpids=[]
for pid in self.pids:
if globalconfig['use_yapi']:
self.Luna_Inject(pid,os.path.abspath('./files/plugins/LunaHook'))
else:
if(self.Luna_CreatePipeAndCheck(pid)):
injectpids.append(pid)
if len(injectpids):
arch=['32','64'][self.is64bit]
injecter=os.path.abspath('./files/plugins/shareddllproxy{}.exe'.format(arch))
dll=os.path.abspath('./files/plugins/LunaHook/LunaHook{}.dll'.format(arch))
print(injecter,os.path.exists(injecter))
print(dll,os.path.exists(dll))
#subprocess.Popen('"{}" dllinject {} "{}"'.format(injecter,pid,dll))
pid=' '.join([str(_) for _ in injectpids])
if any(map(testprivilege,injectpids))==False:
windows.ShellExecute(0,'runas',injecter,'dllinject {} "{}"'.format(pid,dll),None,windows.SW_HIDE)
else:
ret=subprocess.run('"{}" dllinject {} "{}"'.format(injecter,pid,dll)).returncode
if(ret==0):
windows.ShellExecute(0,'runas',injecter,'dllinject {} "{}"'.format(pid,dll),None,windows.SW_HIDE)
threading.Thread(target=self.solveeventthread).start()
@threader
def onprocconnect(self,pid):
time.sleep(savehook_new_data[self.pname]['inserthooktimeout']/1000)
for hookcode in self.needinserthookcode:
self.Luna_InsertHookCode(pid,hookcode)
self.showgamename()
self.flashembedsettings(pid)
def solveeventthread(self):
while self.ending==False:
message=windows.ReadFile(self.hRead,sizeof(Message),None)
if len(message)!=sizeof(Message):break
message=Message.from_buffer_copy(message)
_type=message.type
if _type in [0,1]:
pid=(message.pid)
if _type==0:
self.onprocconnect(pid)
elif _type==1:
gobject.baseobject.hookselectdialog.sysmessagesignal.emit('{} disconenct'.format(pid))
elif _type in [2,3]:
if _type==2:
self.onnewhook(message.hc,message.hn,message.tp)
elif _type==3:
self.onremovehook(message.tp)
elif _type==4:
self.handle_output(message.hc,message.hn,message.tp,cast(message.stringptr,c_wchar_p).value)
elif _type==5:
gobject.baseobject.hookselectdialog.sysmessagesignal.emit(cast(message.stringptr,c_wchar_p).value)
elif _type==6:
self.newhookinsert(message.addr,cast(message.stringptr,c_wchar_p).value)
elif _type==7:
self.getembedtext(cast(message.stringptr,c_wchar_p).value,message.tp)
if message.stringptr:
self.Luna_cfree(message.stringptr)
def newhookinsert(self,addr,hcode):
for _hc,_addr,_ctx1,_ctx2 in savehook_new_data[self.pname]['embedablehook']:
if hcode==_hc:
self.useembed(addr,_ctx1,_ctx2,True)
def getembedtext(self,text,tt):
def getembedtext(self,text,tp):
if globalconfig['autorun']==False:
self.embedcallback(text,0,text)
return
if self.checkisusingembed(tt.tp.addr,tt.tp.ctx,tt.tp.ctx2):
if self.checkisusingembed(tp.addr,tp.ctx,tp.ctx2):
self.newline.put((text,False, functools.partial(self.embedcallback,text),True))
def embedcallback(self,text,_unused,trans):
self.sharedcell.contents.text=trans
self.notify(self.EMBEDPID,text)
def createembedsharedmem(self,pid):
self.EMBEDPID=pid
fmap1=windows.OpenFileMapping(windows.FILE_MAP_READ|0x2,False,'EMBED_SHARED_MEM'+str(pid))
address1=windows.MapViewOfFile(fmap1, windows.FILE_MAP_READ|0x2, 4096)
self.sharedcell=ctypes.cast(address1,ctypes.POINTER(define.EmbedSharedMem))
self.flashembedsettings()
def flashembedsettings(self):
if self.sharedcell is None:return
self.sharedcell.contents.waittime=int(1000* globalconfig['embedded']['timeout_translate'])
self.sharedcell.contents.fontCharSet=2#static_data["charsetmap"][globalconfig['embedded']['changecharset_charset']]
self.sharedcell.contents.fontCharSetEnabled=False#globalconfig['embedded']['changecharset']
self.sharedcell.contents.fontFamily=globalconfig['embedded']['changefont_font'] if globalconfig['embedded']['changefont'] else ''
self.sharedcell.contents.spaceadjustpolicy=globalconfig['embedded']['insertspace_policy']
self.sharedcell.contents.keeprawtext=globalconfig['embedded']['keeprawtext']
def notify(self,pid,text):
_b=text.encode('utf-16-le')
def hs(text):
_b=text.encode('utf-16-le')
u64=ctypes.c_uint64(5381)
for i in range(len(_b)):
u64=ctypes.c_uint64((u64.value<<5)+u64.value+_b[i])
return (u64.value)
hash_=hs(text)
eventName = define.LUNA_NOTIFY % (pid, hash_)
ev = windows.AutoHandle(windows.CreateEvent( False, False, eventName) )
windows.SetEvent(ev)
for pid in self.pids:
self.Luna_embedcallback(pid,text,trans)
def flashembedsettings(self,pid=None):
if pid:
pids=[pid]
else:
pids=self.pids
for pid in pids:
self.Luna_EmbedSettings(pid,
int(1000* globalconfig['embedded']['timeout_translate']),
2, #static_data["charsetmap"][globalconfig['embedded']['changecharset_charset']]
False,#globalconfig['embedded']['changecharset']
globalconfig['embedded']['changefont_font'] if globalconfig['embedded']['changefont'] else '',
globalconfig['embedded']['insertspace_policy'],
globalconfig['embedded']['keeprawtext'])
def onremovehook(self,tp):
toremove=[]
self.lock.acquire()
@ -131,26 +240,26 @@ class texthook(basetext ):
gobject.baseobject.hookselectdialog.removehooksignal.emit(key)
self.hookdatacollecter.pop(key)
self.lock.release()
def parsetextthread(self,textthread):
def parsetextthread(self,hc,hn,tp):
key=(
textthread.tp.processId,
textthread.tp.addr,
textthread.tp.ctx,
textthread.tp.ctx2,
textthread.hp.name.decode('ascii'),
textthread.hpcode
tp.processId,
tp.addr,
tp.ctx,
tp.ctx2,
hn.decode('ascii'),
hc
)
return key
def match_compatibility(self,key,autostarthookcode):
base= (key[2]&0xffff,key[3]&0xffff,key[5])==(autostarthookcode[2]&0xffff,autostarthookcode[3]&0xffff,autostarthookcode[5])
name=((key[-1][:8]=='UserHook' and autostarthookcode[-1][:8]=='UserHook' )or(key[-1]==autostarthookcode[-1]))
return base and name
def onnewhook(self,textthread):
def onnewhook(self,hc,hn,tp):
key=self.parsetextthread(textthread)
key=self.parsetextthread(hc,hn,tp)
if self.isremoveuseless:
if key[1] not in [_[1] for _ in self.autostarthookcode]:
self.RPC.RemoveHook(key[0],key[1])
self.Luna_RemoveHook(key[0],key[1])
return False
self.lock.acquire()
@ -164,13 +273,11 @@ class texthook(basetext ):
self.hookdatacollecter[key]=[]
self.hooktypecollecter[key]=0
gobject.baseobject.hookselectdialog.addnewhooksignal.emit(key ,select,[textthread])
gobject.baseobject.hookselectdialog.addnewhooksignal.emit(key ,select,[hc,hn,tp])
self.lock.release()
return True
def setsettings(self):
self.RPC.setting.timeout=globalconfig['textthreaddelay']
self.RPC.setting.flushbuffersize=globalconfig['flushbuffersize']
self.RPC.setting.defaultcodepag=self.codepage()
self.Luna_Settings(globalconfig['textthreaddelay'],globalconfig['direct_filterrepeat'],self.codepage() ,globalconfig['flushbuffersize'])
def codepage(self):
try:
cpi=savehook_new_data[self.pname]["codepage_index"]
@ -180,7 +287,7 @@ class texthook(basetext ):
return cp
def defaultsp(self):
usestruct=define.SearchParam()
usestruct=SearchParam()
if not self.is64bit:
usestruct.pattern=bytes([0x55,0x8b,0xec])
usestruct.length=3
@ -200,44 +307,44 @@ class texthook(basetext ):
usestruct.codepage=self.codepage()
usestruct.boundaryModule=os.path.basename(self.pname)
return usestruct
@threader
def findhook(self,usestruct):
self.savefound={}
self.foundnum=0
def __waitforok():
#time.sleep(usestruct.searchTime/1000)
_last=0
for i in range(100):
#print(self.foundnum)
if _last!=self.foundnum or _last==0:
_last=self.foundnum
time.sleep(1)
else:
break
print('??',_last,self.foundnum)
gobject.baseobject.hookselectdialog.getfoundhooksignal.emit(self.savefound.copy())
def _(hc,text):
# try:print(hc,text)
# except:print(hc)
if hc not in self.savefound:
self.savefound[hc]=[]
self.savefound[hc].append(text)
if self.foundnum==0:
threading.Thread(target=__waitforok).start()
self.foundnum+=1
#print(self.foundnum)
for pid in self.pids:
self.RPC.FindHooks(pid,usestruct,_)
savefound={}
pids=self.pids.copy()
def inserthook(self,hookcode):
for pid in self.pids:
print(hookcode)
self.RPC.InsertHookCode(pid,hookcode)
headers={}
waiters={}
for pid in pids:
headers[pid]=HANDLE()
count=POINTER(c_int)()
waiters[pid]=count
self.Luna_FindHooks(pid,usestruct,pointer(headers[pid]),pointer(count))
def ReadThread(hread):
while True:
message=windows.ReadFile(hread,sizeof(simplehooks),None)
if len(message)!=sizeof(simplehooks):break
message=simplehooks.from_buffer_copy(message)
hc=message.hookcode
text=cast(message.text,c_wchar_p).value
if hc not in savefound:
savefound[hc]=[]
savefound[hc].append(text)
self.Luna_cfree(message.text)
windows.CloseHandle(hread)
threading.Thread(target=ReadThread,args=(headers[pid],)).start()
for pid in pids:
self.Luna_FindHooks_waiting(waiters[pid])
gobject.baseobject.hookselectdialog.getfoundhooksignal.emit(savefound)
def inserthook(self,hookcode):
succ=True
for pid in self.pids:
succ=self.Luna_InsertHookCode(pid,hookcode) and succ
if succ==False:
getQMessageBox(gobject.baseobject.hookselectdialog,"Error","Invalie Hook Code Format!")
def removehook(self,pid,address):
for pid in self.pids:
self.RPC.RemoveHook(pid,address)
self.Luna_RemoveHook(pid,address)
def delaycollectallselectedoutput(self):
collector=[]
while True:
@ -249,16 +356,15 @@ class texthook(basetext ):
self.newline.put(collector)
self.runonce_line=collector
collector=[]
def handle_output(self,textthread,output):
#print(output)
key=self.parsetextthread(textthread)
def handle_output(self,hc,hn,tp,output):
key=self.parsetextthread(hc,hn,tp)
if globalconfig['filter_chaos_code'] and checkchaos(output):
return
if key not in self.hookdatacollecter:
if self.onnewhook(textthread)==False:
if self.onnewhook(hc,hn,tp)==False:
return
self.lock.acquire()
if self.hooktypecollecter[key]==1:
@ -284,31 +390,13 @@ class texthook(basetext ):
self.lock.release()
def checkisusingembed(self,address,ctx1,ctx2):
if self.sharedcell is None:return
for i in range(10):
if(self.sharedcell.contents.using[i]):
if (self.sharedcell.contents.addr[i],self.sharedcell.contents.ctx1[i],self.sharedcell.contents.ctx2[i])==(address,ctx1,ctx2):
return True
return False
for pid in self.pids:
if self.Luna_checkisusingembed(pid,address,ctx1,ctx2):
return True
return False
def useembed(self,address,ctx1,ctx2,use):
if self.sharedcell is None:return
for i in range(10):
if(self.sharedcell.contents.using[i]):
if (self.sharedcell.contents.addr[i],self.sharedcell.contents.ctx1[i],self.sharedcell.contents.ctx2[i])==(address,ctx1,ctx2):
if use==False:
self.sharedcell.contents.addr[i]=0
self.sharedcell.contents.ctx1[i]=0
self.sharedcell.contents.ctx2[i]=0
self.sharedcell.contents.using[i]=0
if use:
for i in range(10):
if(self.sharedcell.contents.using[i]==0):
self.sharedcell.contents.using[i]=1
self.sharedcell.contents.addr[i]=address
self.sharedcell.contents.ctx1[i]=ctx1
self.sharedcell.contents.ctx2[i]=ctx2
break
for pid in self.pids:
self.Luna_useembed(pid,address,ctx1,ctx2,use)
def gettextthread(self ):
text=self.newline.get()
@ -320,8 +408,7 @@ class texthook(basetext ):
return self.runonce_line
def end(self):
for pid in self.pids:
self.RPC.Detach(pid)
self.RPC.end()
self.Luna_Detach(pid)
time.sleep(0.1)
super().end()

View File

@ -1,15 +1,11 @@
from ctypes import c_uint,c_bool,POINTER,c_char_p,c_uint64,c_wchar_p,pointer,CDLL,Structure,c_void_p,cast
import platform,os
import platform,os,gobject
if platform.architecture()[0]=='64bit':
pythonbit='64'
else:
pythonbit='32'
try:
if platform.system() != "Windows" or int(platform.version().split('.')[0])<6:
raise Exception()
winrtutilsdll=CDLL(os.path.abspath('./files/plugins/winrtutils{}.dll'.format(pythonbit)) )
winrtutilsdll=CDLL(gobject.GetDllpath(('winrtutils32.dll','winrtutils64.dll')))
except:
winrtutilsdll=0

View File

@ -1,11 +1,7 @@
from ctypes import c_uint,c_bool,POINTER,c_char_p,c_uint64,c_wchar_p,pointer,CDLL,c_int,Structure,c_void_p,cast,memmove,create_unicode_buffer,create_string_buffer,c_size_t,windll
import platform,os
if platform.architecture()[0]=='64bit':
pythonbit='64'
else:
pythonbit='32'
utilsdll=CDLL(os.path.abspath('./files/plugins/winsharedutils{}.dll'.format(pythonbit)) )
import os,gobject
utilsdll=CDLL(gobject.GetDllpath(('winsharedutils32.dll','winsharedutils64.dll')))
_freewstringlist=utilsdll.freewstringlist
_freewstringlist.argtypes=POINTER(c_wchar_p),c_uint
@ -77,8 +73,7 @@ def distance(s1,s2):
class mecabwrap:
def __init__(self,mecabpath) -> None:
self.kks=_mecab_init(mecabpath.encode('utf8'),os.path.abspath('./files/plugins/libmecab{}.dll'.format(pythonbit)) )
self.kks=_mecab_init(mecabpath.encode('utf8'),gobject.GetDllpath('libmecab.dll') )
def __del__(self):
_mecab_end(self.kks)
def parse(self,text):

View File

@ -118,6 +118,8 @@
"isshowhira": false,
"locktools": true,
"showfanyisource": false,
"use_yapi":true,
"showfanyi":true,
"autoread": false,
"show_fenci": false,
"jiamingcolor": "black",
@ -465,7 +467,7 @@
},
"_6": {
"use": false,
"name": "显示/隐藏历史翻译",
"name": "显示/隐藏历史翻译和调试输出",
"key1": -1,
"key2": -1,
"keystring": ""

File diff suppressed because one or more lines are too long

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "نص طول المخزن المؤقت",
"显示/隐藏历史翻译和调试输出": "عرض / إخفاء تاريخ الترجمة وتصحيح الأخطاء الناتج",
"历史翻译和调试输出": "تاريخ الترجمة وتصحيح الأخطاء الناتج",
"调试输出": "التصحيح الناتج"
"调试输出": "التصحيح الناتج",
"显示翻译": "عرض الترجمة",
"使用YAPI注入": "استخدام حقن YAPI"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "文字緩衝區長度",
"显示/隐藏历史翻译和调试输出": "顯示/隱藏歷史翻譯和調試輸出",
"历史翻译和调试输出": "歷史翻譯和調試輸出",
"调试输出": "調試輸出"
"调试输出": "調試輸出",
"显示翻译": "顯示翻譯",
"使用YAPI注入": "使用YAPI注入"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Text buffer length",
"显示/隐藏历史翻译和调试输出": "Show/hide historical translation and debugging output",
"历史翻译和调试输出": "Historical translation and debugging output",
"调试输出": "Debugging output"
"调试输出": "Debugging output",
"显示翻译": "Display translation",
"使用YAPI注入": "Using YAPI injection"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Longitud del colchón de texto",
"显示/隐藏历史翻译和调试输出": "Mostrar / ocultar la traducción histórica y depurar la salida",
"历史翻译和调试输出": "Traducción histórica y salida de depuración",
"调试输出": "Salida de depuración"
"调试输出": "Salida de depuración",
"显示翻译": "Mostrar traducción",
"使用YAPI注入": "Inyección con Yapi"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Longueur du tampon de texte",
"显示/隐藏历史翻译和调试输出": "Afficher / masquer la traduction historique et la sortie de débogage",
"历史翻译和调试输出": "Traduction historique et sortie de débogage",
"调试输出": "Sortie de débogage"
"调试输出": "Sortie de débogage",
"显示翻译": "Afficher la traduction",
"使用YAPI注入": "Injection avec Yapi"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Lunghezza buffer di testo",
"显示/隐藏历史翻译和调试输出": "Mostra/nasconde l'output storico di traduzione e debug",
"历史翻译和调试输出": "Risultato storico di traduzione e debug",
"调试输出": "Debug output"
"调试输出": "Debug output",
"显示翻译": "Mostra traduzione",
"使用YAPI注入": "Uso dell'iniezione di YAPI"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "テキストバッファ長",
"显示/隐藏历史翻译和调试输出": "履歴翻訳とデバッグ出力の表示/非表示",
"历史翻译和调试输出": "履歴翻訳とデバッグ出力",
"调试输出": "デバッグ出力"
"调试输出": "デバッグ出力",
"显示翻译": "翻訳を表示",
"使用YAPI注入": "YAPI注入を使用する"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "텍스트 버퍼 길이",
"显示/隐藏历史翻译和调试输出": "히스토리 번역 및 디버그 출력 표시 / 숨기기",
"历史翻译和调试输出": "역사 번역 및 디버그 출력",
"调试输出": "출력 디버그"
"调试输出": "출력 디버그",
"显示翻译": "번역 표시",
"使用YAPI注入": "YAPI 주입 사용"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Długość bufora tekstu",
"显示/隐藏历史翻译和调试输出": "Pokaż/ukryj historyczne tłumaczenie i wyjście debugowania",
"历史翻译和调试输出": "Historiczne tłumaczenie i debugowanie",
"调试输出": "Wyjście debugowania"
"调试输出": "Wyjście debugowania",
"显示翻译": "Wyświetl tłumaczenie",
"使用YAPI注入": "Zastosowanie wstrzykiwań YAPI"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Длина буфера текста",
"显示/隐藏历史翻译和调试输出": "Показать / скрыть исторический перевод и отладочный вывод",
"历史翻译和调试输出": "Исторический перевод и отладка вывода",
"调试输出": "Отладочный вывод"
"调试输出": "Отладочный вывод",
"显示翻译": "Показать перевод",
"使用YAPI注入": "Использовать инъекцию YAPI"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "ความยาวบัฟเฟอร์ข้อความ",
"显示/隐藏历史翻译和调试输出": "แสดง / ซ่อนการแปลประวัติและการแก้จุดบกพร่องเอาท์พุท",
"历史翻译和调试输出": "การแปลประวัติและการแก้จุดบกพร่องเอาท์พุท",
"调试输出": "การว่าจ้างเอาท์พุท"
"调试输出": "การว่าจ้างเอาท์พุท",
"显示翻译": "แสดงคำแปล",
"使用YAPI注入": "ใช้ YAPI ฉีด"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Metin buffer uzunluğu",
"显示/隐藏历史翻译和调试输出": "Tarihi çevirimi ve arızasızlandırma çıkışını göster/gizle",
"历史翻译和调试输出": "Tarihi çeviri ve hata ayıklama çıkışı",
"调试输出": "Hata ayıklama çıkışı"
"调试输出": "Hata ayıklama çıkışı",
"显示翻译": "Çeviri göster",
"使用YAPI注入": "YAPI injeksiyonu kullanıyor"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Довжина текстового буфера",
"显示/隐藏历史翻译和调试输出": "Показувати/сховати історичний переклад і вивід зневаджування",
"历史翻译和调试输出": "Історічний переклад і вивід зневаджування",
"调试输出": "Вивод зневаджування"
"调试输出": "Вивод зневаджування",
"显示翻译": "Показувати переклад",
"使用YAPI注入": "Використання інструкції YAPI"
}

View File

@ -685,5 +685,7 @@
"文本缓冲区长度": "Chiều dài bộ đệm văn bản",
"显示/隐藏历史翻译和调试输出": "Hiển thị/ẩn lịch sử dịch và đầu ra gỡ lỗi",
"历史翻译和调试输出": "Lịch sử dịch và gỡ lỗi đầu ra",
"调试输出": "Đầu ra gỡ lỗi"
"调试输出": "Đầu ra gỡ lỗi",
"显示翻译": "Hiện bản dịch",
"使用YAPI注入": "Sử dụng YAPI Injection"
}

View File

@ -686,5 +686,6 @@
"历史翻译和调试输出": "",
"历史翻译": "",
"调试输出": "",
"显示/隐藏历史翻译": ""
"显示翻译": "",
"使用YAPI注入": ""
}

View File

@ -6,27 +6,15 @@ if x86:
nuitkadist=r'..\build\x86\LunaTranslator_main.dist'
targetdir=r'..\build\LunaTranslator_x86'
launch=r'..\plugins\exec\builds\_x86'
badcdlls= [
'libcurl-x64.dll','libmecab64.dll',
'ocr64.dll',
'winsharedutils64.dll','winrtutils64.dll',
r'brotli\x64\brotlicommon.dll',
r'brotli\x64\brotlidec.dll',
]
downlevel=f'C:\Windows\SysWOW64\downlevel'
target='LunaTranslator_x86.zip'
baddll='DLL64'
else:
baddll='DLL32'
target='LunaTranslator.zip'
launch=r'..\plugins\exec\builds\_x64'
nuitkadist=r'..\build\x64\LunaTranslator_main.dist'
targetdir=r'..\build\LunaTranslator'
badcdlls= [
'libcurl.dll','libmecab32.dll',
'ocr32.dll',
'winsharedutils32.dll','winrtutils32.dll',
r'brotli\x86\brotlicommon.dll',
r'brotli\x86\brotlidec.dll',
]
downlevel=f'C:\Windows\system32\downlevel'
targetdir_in=rf'{targetdir}\LunaTranslator'
def get_import_table(file_path):
@ -62,9 +50,7 @@ for f in [
for f in ['imageformats','platforms','styles']:
os.rename(rf'{targetdir_in}\PyQt5\qt-plugins\{f}',rf'{targetdir_in}\{f}')
for f in badcdlls:
remove(rf'{targetdir}\files\plugins\{f}')
remove(rf'{targetdir}\files\plugins\{baddll}')
collect=[]
for _dir,_,fs in os.walk(targetdir):