Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from ctypes import *
- from PyQt4 import QtCore,QtGui
- import sys,time,pickle
- #Shortening names
- button = QtGui.QPushButton
- label = QtGui.QLabel
- textbox = QtGui.QLineEdit
- checkbox = QtGui.QCheckBox
- listbox = QtGui.QListWidget
- combobox = QtGui.QComboBox
- #This function roughly equals "process.GetProcessesByName(name)" (in vb) translated into python. It return the procees handle and the procees pid (handle,PID).
- #It only work for 32 bits process!
- #For more informations see : http://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx
- def openByName(access,handle,name):
- kernel32 = windll.kernel32
- psapi = windll.psapi
- arr = c_ulong * 256
- lpidProcess = arr()
- cbNeeded = c_ulong()
- hModule = c_ulong()
- count = c_ulong()
- modname = c_buffer(30)
- psapi.EnumProcesses(byref(lpidProcess),sizeof(lpidProcess),byref(cbNeeded))
- for pid in lpidProcess:
- hProcess = kernel32.OpenProcess(0x0400|0x0010,False, pid)
- if hProcess:
- psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count))
- psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname))
- a = ''
- for i in modname:
- if i != b'\x00':
- a += str(i)
- if a != name:
- for i in range(modname._length_):
- modname[i]=b'\x00'
- kernel32.CloseHandle(hProcess)
- else:
- kernel32.CloseHandle(hProcess)
- handle = kernel32.OpenProcess(access,handle,pid)
- return handle,pid
- return 0,0
- #This is the same function as above but edited to return a list of process
- def listProcess():
- processList = []
- kernel32 = windll.kernel32
- psapi = windll.psapi
- arr = c_ulong * 256
- lpidProcess = arr()
- cbNeeded = c_ulong()
- hModule = c_ulong()
- count = c_ulong()
- modname = c_buffer(30)
- psapi.EnumProcesses(byref(lpidProcess),sizeof(lpidProcess),byref(cbNeeded))
- for pid in lpidProcess:
- hProcess = kernel32.OpenProcess(0x0400|0x0010,False, pid)
- if hProcess:
- psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count))
- psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname))
- a = ''
- for i in modname:
- if i != b'\x00' and i != b'\xd1':
- a += str(i)
- processList.append(a)
- for i in range(modname._length_):
- modname[i]=b'\x00'
- kernel32.CloseHandle(hProcess)
- #last check, 2 loop because 1 is not enough:
- for i in range (10):
- for i in processList:
- if not '.exe' in i:
- processList.remove(i)
- return processList
- class injectorCore(QtCore.QThread):# !!! ACTUAL INJECTOR CODE IS IN HERE !!!
- def __init__(self,name,Dict):
- super(injectorCore,self).__init__()
- self.name = name
- self.Dict = Dict
- def run(self):
- self.inject()
- def inject(self):
- self.errorlog = ''
- for path,calls in self.Dict.items():
- #Check is dll path is valid
- try:
- open(path,'rb')
- valid = True
- except:
- self.errorlog += "ERROR : Could not inject {0}, Reason: The file does not exist/ Can't access file.\n".format(path)
- valid = False
- if valid == True:
- #Try to open a process
- hprocess,pid = openByName(0x0400|0x0010|0x0020|0x0008|0x0002,0,self.name)
- if hprocess == 0 and gui.injectAtStartup == 0:
- gui.statusBar().showMessage('Could not find process, aborting.')
- gui.injectBtn.setText('Inject!')
- self.terminate()
- return 0
- elif hprocess == 0 and gui.injectAtStartup == 2:
- while hprocess == 0:
- gui.statusBar().showMessage('Waiting for {0}'.format(self.name))
- hprocess,pid = openByName(0x0400|0x0010|0x0020|0x0008|0x0002,0,self.name)
- time.sleep(0.1) #Not to overload cpu
- kernel32 = windll.Kernel32 #Kernel 32 dll
- kernel32 = windll.LoadLibrary('C:\Windows\System32\kernel32.dll')
- null = c_int(0) #A c null
- LEN_DLL = len(path)+1 # Get the length of the DLL PATH
- #Get the address of loadlibrary function
- module = kernel32.GetModuleHandleA("kernel32.dll")
- lib_addr = kernel32.GetProcAddress( module,"LoadLibraryA")
- # get some read/writable mem in target proc so target can read some data we give it
- str_addr = kernel32.VirtualAllocEx ( hprocess,null,c_long(LEN_DLL),0x00001000|0x00002000,4 )
- # write the dllname we want to run to the remote memory
- kernel32.WriteProcessMemory (hprocess , str_addr ,path , c_long(LEN_DLL) , null)
- #Creating Remote Thread to load our DLL
- thread = kernel32.CreateRemoteThread ( hprocess ,null,null ,
- c_long( lib_addr ) ,c_long( str_addr) , null,null)
- time.sleep(0.1) #To ensure that everything is correct
- if thread == 0:
- self.errorlog += "ERROR : Could not inject {0}, Reason: UNKNOW (64 bit process?).\n".format(path)
- else:
- self.errorlog += "SUCCESS : {0} Injected\n".format(path)
- for a,b in calls.items(): #Function calling
- #{'DLL NAME':{'FuncCall1':['NAME','Parameter','Iteration','Type']},'FuncCall2':['NAME','Parameter','Iteration','Type'],etc}
- self.callFunction(hprocess,thread,b[0],b[1],b[2],b[3],path)
- open('info.log','w').write(self.errorlog)
- if 'ERROR' in open('info.log','r').read() and gui.closeAfterInject != 2:
- gui.statusBar().showMessage('Some error occurred while injecting, see info.log.')
- elif not 'ERROR' in open('info.log','r').read() and gui.closeAfterInject != 2:
- gui.statusBar().showMessage('Injection successfull.')
- gui.injectBtn.setText('Inject!')
- #Close the injector if needed.
- if gui.closeAfterInject == 2:
- gui.processListWindow.hide() #The user might be an idiot and still have this window open...
- gui.funcWindow.hide() #Again...
- gui.close()
- self.close()
- def callFunction(self,hprocess,thread,name,arg,it,Type,path): # !!! HERE IS THE CODE USED TO CALL A FUNCTION IN THE DLL !!!
- it = int(it)
- name = str(name)
- #Value converting
- try:
- if Type == 'None':
- arg = None
- elif Type == 'String':
- arg = c_char_p(str(arg))
- elif Type == 'Integer':
- arg = c_int( int(arg) )
- elif Type == 'Float':
- arg = c_float( float(arg) )
- elif Type == 'Double':
- arg = c_double( float(arg) )
- elif Type == 'Boolean':
- arg = c_bool(bool(arg))
- except :
- self.errorlog += " ERROR : Could not call {0} using {1} as {2}, Reason: Value could not be converted.\n".format(name,arg,Type)
- return 0
- kernel32 = windll.Kernel32 #Kernel 32 dll
- null = c_int(0) #A c null
- exitcode = c_int()
- a = kernel32.GetExitCodeThread( thread,byref(exitcode))
- findoff = kernel32.LoadLibraryA(path)
- modfunc = kernel32.GetProcAddress ( findoff, name )
- if modfunc == 0:
- self.errorlog += " ERROR : Could not call {0} using {1} as {2}, Reason: This function do not exist.\n".format(name,arg,Type)
- return 0
- offset = modfunc - findoff
- exitcode = exitcode.value + offset
- for i in range(it):
- try:
- if arg != None:
- thread2 = kernel32.CreateRemoteThread ( hprocess ,null,null , # proc , sa, stacksize,
- c_long( exitcode ) ,arg,null ,null) # start_addr, args, flags,out[ID]
- if thread2 == 0:
- self.errorlog += " ERROR : Could not call {0} using {1} as {2}, Reason: Wrong argument.\n".format(name,arg,Type)
- else:
- thread2 = kernel32.CreateRemoteThread ( hprocess ,null,null , # proc , sa, stacksize,
- c_long( exitcode ) ,null,null ,null) # start_addr, args, flags,out[ID]
- if thread2 == 0:
- self.errorlog += " ERROR : Could not call {0} using {1} as {2}, Reason: Wrong argument.\n".format(name,arg,Type)
- except:
- self.errorlog += " ERROR : Could not call {0} using {1} as {2}, Reason: UNKNOW.\n".format(name,arg,Type)
- class InjectorGUI(QtGui.QMainWindow):
- def __init__(self):
- super(InjectorGUI,self).__init__() #This line roughly make "self" = QtGui.QMainWindow
- #Global variables of the program are inited here
- self.dllPath = {} #{'DLL NAME':{'FuncCall1':['NAME','Parameter','Iteration','Type']},'FuncCall2':['NAME','Parameter','Iteration','Type'],etc}
- self.processName = ''
- self.injectAtStartup = 0
- self.closeAfterInject = 0
- self.itemSelected = None
- #This start the function who init the main window and other windows.
- self.initMain()
- self.initProcessList()
- self.initFuncList()
- self.initDllList()
- def initMain(self): #Main window is inited here
- def actions(*argv): #Main window actions are handled here (*argv will hold extra data sent by the widget)
- sender = self.sender() #This get the last widget who activated this functions.
- if sender == self.getProcessBtn:
- self.processListWindow.show() # See "def initProcessList(self)"
- if sender == self.getDllBtn:
- self.dllWindow.show()
- if sender == self.injectAtStartupCB:
- self.injectAtStartup = argv[0] #Note: argv[0] is the current Qt.CheckState of the checkbox (0 if unchecked,2 if checked).
- if sender == self.closeAfterInjectCB:
- self.closeAfterInject = argv[0] #Note: argv[0] is the current Qt.CheckState of the checkbox (0 if unchecked,2 if checked).
- if sender == self.injectBtn:
- if sender.text() == 'Inject!':
- if not '0 dll loaded...' in self.dllTxtBox.text():
- sender.setText('Cancel')
- self.processName = str(self.processTxtBox.text())
- self.core = injectorCore(self.processName,self.dllPath)
- self.core.start()
- else:
- resp = QtGui.QMessageBox.critical(self.funcWindow,'Python injector','I think you forgot to add a dll.',QtGui.QMessageBox.Ok)
- else:
- gui.statusBar().showMessage('Injection cancelled')
- sender.setText('Inject!')
- self.core.terminate()
- del self.core
- if sender == self.saveAction:
- saveFilename = 'config.dat'
- data = (self.dllPath,
- str(self.processTxtBox.text()),
- int(self.injectAtStartupCB.checkState()),
- int(self.closeAfterInjectCB.checkState()),
- str(self.dllTxtBox.text()))
- f = open(saveFilename, 'wb')
- pickle.dump(data, f) # dump the object to a file
- f.close()
- QtGui.QMessageBox.information(self.funcWindow,'Python injector','Configuration succesfully saved!',QtGui.QMessageBox.Ok)
- if sender == self.loadAction:
- self.dllListBox.clear()
- openFilename = 'config.dat'
- try:
- f = open(openFilename, 'rb')
- except:
- QtGui.QMessageBox.warning(self.funcWindow,'Python injector','No saved configuration found!',QtGui.QMessageBox.Ok)
- return 0
- data = pickle.load(f)
- self.processTxtBox.setText(data[1])
- self.injectAtStartupCB.setCheckState(data[2])
- self.closeAfterInjectCB.setCheckState(data[3])
- self.dllTxtBox.setText(data[4])
- self.dllPath = data[0]
- for a,b in self.dllPath.items():
- item = QtGui.QListWidgetItem(a);item.content = b
- self.dllListBox.addItem(item)
- QtGui.QMessageBox.information(self.funcWindow,'Python injector','Configuration succesfully loaded!',QtGui.QMessageBox.Ok)
- def initWidgets(): #Main window widgets are inited here.
- #Note: I only use "self." in the name of the widgets if I need to get their value outside this functions (ex: When executing actions()).
- processLbl = label('Process:',self);processLbl.move(10,45)
- dllLbl = label('Dll:',self);dllLbl.move(10,85)
- #Menu bar is inited here
- menubar = self.menuBar()
- self.saveAction = QtGui.QAction('&Save', self);self.saveAction.triggered.connect(actions)
- self.loadAction = QtGui.QAction('&Load', self);self.loadAction.triggered.connect(actions)
- fileMenu = menubar.addMenu('&Option');fileMenu.addAction(self.saveAction);fileMenu.addAction(self.loadAction)
- self.injectBtn = button('Inject!',self);self.injectBtn.setGeometry(190,135,150,60);self.injectBtn.clicked.connect(actions)
- self.getProcessBtn = button('...',self);self.getProcessBtn.setGeometry(310,55,30,20);self.getProcessBtn.clicked.connect(actions)
- self.getDllBtn = button('...',self);self.getDllBtn.setGeometry(310,95,30,20);self.getDllBtn.clicked.connect(actions)
- self.injectAtStartupCB = checkbox('Inject at startup',self);self.injectAtStartupCB.setGeometry(10,140,160,17);self.injectAtStartupCB.stateChanged.connect(actions)
- self.injectAtStartupCB.setToolTip('Check this if the process is not yet started')
- self.closeAfterInjectCB = checkbox('Close after inject',self);self.closeAfterInjectCB.setGeometry(10,170,160,17);self.closeAfterInjectCB.stateChanged.connect(actions)
- self.processTxtBox = textbox('Process.exe',self);self.processTxtBox.setGeometry(80,45,220,30)
- self.dllTxtBox = textbox('0 dll loaded...',self);self.dllTxtBox.setGeometry(80,85,220,30);self.dllTxtBox.setFont(self.smallFont)#Note : fonts are defined in style script.
- self.dllTxtBox.setEnabled(False)
- try:
- exec(open('QNovaDark.py').read()) in locals(),globals() #This line execute a python file who set the palette (style) and the fonts of the application.
- except:
- QtGui.QMessageBox.warning(self,'Python injector','Cannot find style script... too bad for you.',QtGui.QMessageBox.Ok)
- self.font = QtGui.QFont('MS Shell Dlg 2',pointSize = 13)
- self.smallFont = QtGui.QFont('MS Shell Dlg 2',pointSize = 9)
- #The main window properties are inited here
- self.setFixedSize(350,225)
- self.setFont(self.font) #Note font are defined in style script
- self.setWindowTitle('PyInject - Python injector')
- self.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowCloseButtonHint)
- self.statusBar().showMessage('Ready')
- initWidgets()
- self.show()
- def initProcessList(self): #Another window
- def actions(*argv): #Main window actions are handled here (*argv will hold extra data sent by the widget)
- sender = self.sender() #This get the last widget who activated this functions.
- if sender == self.chooseProcess:
- try: #Catch the error when the user click done but has selected nothing.
- self.processTxtBox.setText(self.processList.item(self.processList.currentRow()).text())
- except AttributeError:
- pass
- self.processListWindow.hide()
- if sender == self.refreshBtn:
- self.processList.clear()
- self.processList.addItems(listProcess())
- def initWidgets(wind):#Main window widgets are inited here.
- self.processList = listbox(wind);self.processList.setGeometry(5,5,190,210);self.processList.setFont(self.smallFont) #Note : fonts are defined in style script.
- self.chooseProcess = button('Done',wind);self.chooseProcess.setGeometry(5,217,90,30);self.chooseProcess.clicked.connect(actions)
- self.refreshBtn = button('Refresh',wind);self.refreshBtn.setGeometry(105,217,90,30);self.refreshBtn.clicked.connect(actions)
- #Adding a child window to the main window. THE NEW WIDGET MUST NOT BE PARENTED!!!!!
- self.processListWindow = QtGui.QWidget()
- self.processListWindow.setWindowTitle('Choose a process')
- self.processListWindow.setFixedSize(200,250)
- self.processListWindow.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowCloseButtonHint)
- #self.processListWindow.show() is omitted because this window must be hidden when the program starts.
- initWidgets(self.processListWindow)
- def initFuncList(self):#Another window
- def actions(*argv):
- sender = self.sender()
- if sender == self.addBtn: #Add a call to the list
- def getID(less = False): #Create an ID for the next call
- num = 0;ID = 'func{0}'
- while self.funcCallList.findItems(ID.format(num),QtCore.Qt.MatchStartsWith) != []:
- num += 1
- return(ID.format(num))
- def check(a,b,c): #Simple check to see if the item is already here
- for i in range(self.funcCallList.count()):
- text = self.funcCallList.item(i).text().split('::')
- if text[1] == a and text[2] == b and text[4] == c:
- return self.funcCallList.item(i),text[0],text[4]
- return False,False,False
- ID = getID() #Get the last Id to protect against data overwrithing
- if self.funcName.text() != '' and self.funcArg.text() != '':
- check,i,i2 = check(self.funcName.text(),self.funcArg.text(),self.argType.currentText())
- if check == False:
- self.funcCallList.addItem('{0}::{1}::{2}::1::{3}'.format(ID,self.funcName.text(),self.funcArg.text(),self.argType.currentText()))
- self.funcCallList.sortItems()
- else:
- num = int(str(check.text()).split('::')[3])+1
- check.setText('{0}::{1}::{2}::{3}::{4}'.format(i,self.funcName.text(),self.funcArg.text(),num,i2))
- else:
- QtGui.QMessageBox.warning(self.funcWindow,'Python injector','The function need a title and 1 argument.',QtGui.QMessageBox.Ok)
- if sender == self.remBtn: #Remove a call from the list
- if self.funcCallList.currentRow() != -1:
- self.funcCallList.takeItem(self.funcCallList.currentRow())
- else:
- QtGui.QMessageBox.warning(self.funcWindow,'Python injector','Select a function first!',QtGui.QMessageBox.Ok)
- if sender == self.clrBtn: #Clear all call from the list
- resp = QtGui.QMessageBox.warning(self.funcWindow,'Python injector','Do you really want to remove all items in the list?',QtGui.QMessageBox.Yes|QtGui.QMessageBox.No)
- if resp == QtGui.QMessageBox.Yes:
- self.funcCallList.clear()
- if sender == self.okBtn: #Save the calls to the item
- self.funcCall = {}
- for i in range(self.funcCallList.count()):
- text = self.funcCallList.item(i).text().split('::')
- self.itemSelected.content[str(text[0])] = [str(text[1]),str(text[2]),str(text[3]),str(text[4])]
- QtGui.QMessageBox.information(self.funcWindow,'Python injector','{0} functions call were added.'.format(self.funcCallList.count()),QtGui.QMessageBox.Ok)
- self.funcWindow.hide()
- def initWidgets(wind):
- self.funcName = textbox('Function name here',wind);self.funcName.setGeometry(10,10,200,25)
- self.funcArg = textbox('Function argument',wind);self.funcArg.setGeometry(220,10,130,25)
- self.argType = combobox(wind);self.argType.setGeometry(355,10,80,25);self.argType.addItems(['None','Integer','Boolean','Float','Double','String'])
- self.addBtn = button('Add',wind);self.addBtn.setGeometry(345,160,100,25);self.addBtn.clicked.connect(actions)
- self.remBtn = button('Remove',wind);self.remBtn.setGeometry(235,160,100,25);self.remBtn.clicked.connect(actions)
- self.clrBtn = button('Clear',wind);self.clrBtn.setGeometry(125,160,100,25);self.clrBtn.clicked.connect(actions)
- self.okBtn = button('OK',wind);self.okBtn.setGeometry(15,160,100,25);self.okBtn.clicked.connect(actions)
- self.funcCallList = listbox(wind);self.funcCallList.setGeometry(10,45,430,108);self.funcCallList.setSortingEnabled(True)
- self.funcCallList.setToolTip("Functions call are represented here\n ([ID]::[Function name]::[Argument]::[Time to call]:[Data Type]) .")
- #Adding a child window to the main window. THE NEW WIDGET MUST NOT BE PARENTED!!!!!
- self.funcWindow = QtGui.QWidget()
- self.funcWindow.setFont(self.smallFont)
- self.funcWindow.setWindowTitle('Functions to call')
- self.funcWindow.setFixedSize(450,190)
- self.funcWindow.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowCloseButtonHint)
- #self.funcWindow.show() is omitted because this window must be hidden when the program starts.
- initWidgets(self.funcWindow)
- def initDllList(self): #Another window
- def actions():
- sender = self.sender()
- if sender == self.addDllBtn:#Add a new item and append "content" to it (to contain func call)
- response = QtGui.QFileDialog.getOpenFileName(self.dllWindow,'Choose a dll',filter = '*.dll')
- if response != '' and self.dllListBox.findItems(response,QtCore.Qt.MatchExactly) == [] :
- item = QtGui.QListWidgetItem(response);item.content = {}
- self.dllListBox.addItem(item)
- else:
- QtGui.QMessageBox.warning(self.dllWindow,'Python injector','This dll is already in the list!',QtGui.QMessageBox.Ok)
- if sender == self.remDllBtn: #Simply remove an item from the list
- selected = self.dllListBox.currentRow()
- if selected != -1:
- self.dllListBox.takeItem(selected)
- else:
- QtGui.QMessageBox.warning(self.dllWindow,'Python injector','No dll selected.',QtGui.QMessageBox.Ok)
- if sender == self.manageCallBtn: #Open the manage call window with the information contained in item.content
- selected = self.dllListBox.currentRow()
- if selected != -1:
- self.itemSelected = self.dllListBox.item(selected)
- self.funcCallList.clear()
- for i,c in self.itemSelected.content.items():
- self.funcCallList.addItem('{0}::{1}::{2}::{3}::{4}'.format(i,c[0],c[1],c[2],c[3]))
- self.funcWindow.show()
- else:
- QtGui.QMessageBox.warning(self.dllWindow,'Python injector','No dll selected.',QtGui.QMessageBox.Ok)
- if sender == self.doneBtn: #Save dll informations into self.dllPath
- for i in range(self.dllListBox.count()):
- item = self.dllListBox.item(i)
- name,content = item.text(),item.content
- self.dllPath[str(name)] = content
- self.dllWindow.hide()
- self.dllTxtBox.setText('{0} dll loaded.'.format(self.dllListBox.count()))
- def initWidgets(wind):
- self.dllListBox = listbox(wind);self.dllListBox.setGeometry(10,10,300,240)
- self.addDllBtn = button('Add dll',wind);self.addDllBtn.setGeometry(320,10,90,40);self.addDllBtn.clicked.connect(actions)
- self.remDllBtn = button('Remove dll',wind);self.remDllBtn.setGeometry(320,60,90,40);self.remDllBtn.clicked.connect(actions)
- self.manageCallBtn = button('Manage\nCalls',wind);self.manageCallBtn.setGeometry(320,110,90,40);self.manageCallBtn.clicked.connect(actions)
- self.doneBtn = button('Done',wind);self.doneBtn.setGeometry(320,210,90,40);self.doneBtn.clicked.connect(actions)
- self.dllWindow = QtGui.QWidget()
- self.dllWindow.setFont(self.smallFont)
- self.dllWindow.setWindowTitle('Dll List')
- self.dllWindow.setFixedSize(420,260)
- self.dllWindow.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowCloseButtonHint)
- #self.funcWindow.show() is omitted because this window must be hidden when the program starts.
- initWidgets(self.dllWindow)
- def displayMessageBox(self,title,text,Type):
- if Type == 0:
- QtGui.QMessageBox.information(self,title,text,QtGui.QMessageBox.Ok)
- elif Type == 1:
- QtGui.QMessageBox.warning(self,title,text,QtGui.QMessageBox.Ok)
- elif Type == 2:
- QtGui.QMessageBox.critical(self,title,text,QtGui.QMessageBox.Ok)
- def closeEvent(self,event): #Script to execute when program is closing.
- self.dllWindow.hide()
- self.funcWindow.hide()
- self.processListWindow.hide()
- if __name__ == '__main__':
- global app,gui
- app = QtGui.QApplication(sys.argv)
- gui = InjectorGUI()
- sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement