Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from ctypes import *
- from PyQt4 import QtCore,QtGui
- import sys,time
- #Shortening names
- button = QtGui.QPushButton
- label = QtGui.QLabel
- textbox = QtGui.QLineEdit
- checkbox = QtGui.QCheckBox
- listbox = QtGui.QListWidget
- #This function roughly equals "process.GetProcessesByName(name)" (in vb) translated into python. It return the procees handle and the process 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))
- try:
- a = str(modname.value,'utf8')
- except:
- a= None
- 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 = ''
- try:
- a = str(modname.value,'utf8')
- processList.append(a)
- except:
- pass
- for i in range(modname._length_):
- modname[i]=b'\x00'
- kernel32.CloseHandle(hProcess)
- #l1 is not enough:
- for i in range (10):
- for i in processList:
- if not '.exe' in i:
- processList.remove(i)
- return processList
- class Injector(QtGui.QMainWindow):
- def __init__(self):
- super(Injector,self).__init__() #This line roughly make "self" = QtGui.QMainWindow
- #Global variables of the program are inited here
- self.dllPath = ''
- self.processName = ''
- self.injectAtStartup = 0
- self.closeAfterInject = 0
- self.funcCall = {}
- #This start the function who init the main window and other windows.
- self.initMain()
- self.initProcessList()
- self.initFuncList()
- 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.optionsBtn:
- self.funcWindow.show()
- if sender == self.getDllBtn:
- response = QtGui.QFileDialog.getOpenFileName(self,'Choose dll',filter = '*.dll')
- if response != '': #It return a null string if the user select cancel
- self.dllTxtBox.setText(response)
- 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:
- self.dllPath = str(self.dllTxtBox.text())
- self.processName = str(self.processTxtBox.text())
- self.inject()
- 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,20)
- dllLbl = label('Dll:',self);dllLbl.move(10,80)
- self.injectBtn = button('Inject!',self);self.injectBtn.setGeometry(190,165,150,30);self.injectBtn.clicked.connect(actions)
- self.optionsBtn = button('Options',self);self.optionsBtn.setGeometry(190,125,150,30);self.optionsBtn.clicked.connect(actions)
- self.getProcessBtn = button('...',self);self.getProcessBtn.setGeometry(310,30,30,20);self.getProcessBtn.clicked.connect(actions)
- self.getDllBtn = button('...',self);self.getDllBtn.setGeometry(310,90,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,20,220,30)
- self.dllTxtBox = textbox('.dll path',self);self.dllTxtBox.setGeometry(80,80,220,30);self.dllTxtBox.setFont(self.smallFont)#Note : fonts are defined in style script.
- 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)
- #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.noneArg:
- if argv[0]:
- self.funcArg.setEnabled(False)
- else:
- self.funcArg.setEnabled(True)
- if sender == self.addBtn:
- if self.funcName.text() != '' and self.noneArg.checkState() == 2:
- aList = self.funcCallList.findItems('{0}::{1}'.format(self.funcName.text(),None),QtCore.Qt.MatchStartsWith)
- if aList == []:
- self.funcCallList.addItem('{0}::{1}::1'.format(self.funcName.text(),None))
- else:
- num = int(str(aList[0].text()).split('::')[2])+1
- aList[0].setText('{0}::{1}::{2}'.format(self.funcName.text(),None,num))
- elif self.funcName.text() != '' and self.funcArg.text() != '':
- aList = self.funcCallList.findItems('{0}::{1}'.format(self.funcName.text(),self.funcArg.text()),QtCore.Qt.MatchStartsWith)
- if aList == []:
- self.funcCallList.addItem('{0}::{1}::1'.format(self.funcName.text(),self.funcArg.text()))
- else:
- num = int(str(aList[0].text()).split('::')[2])+1
- aList[0].setText('{0}::{1}::{2}'.format(self.funcName.text(),self.funcArg.text(),num))
- else:
- QtGui.QMessageBox.warning(self.funcWindow,'Python injector','The function need a title and 1 argument.',QtGui.QMessageBox.Ok)
- if sender == self.remBtn:
- 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:
- 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:
- self.funcCall = {}
- for i in range(self.funcCallList.count()):
- text = self.funcCallList.item(i).text().split('::')
- self.funcCall[str(text[0])] = [str(text[1]),str(text[2])]
- 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(230,10,150,25)
- self.noneArg = checkbox('None',wind);self.noneArg.setGeometry(385,10,150,25);self.noneArg.stateChanged.connect(actions)
- 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.setToolTip("Functions call are represented here\n ([Function name]::[Argument]::[Number of time to send]) .")
- #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 inject(self): # !!! ACTUAL INJECTOR CODE IS IN HERE !!!
- #Check is dll path is valid
- try:
- open(self.dllPath,'rb')
- except:
- QtGui.QMessageBox.critical(self,'Python injector','Cannot find dll.',QtGui.QMessageBox.Ok)
- return 0
- #Try to open a process
- hprocess,pid = openByName(0x0400|0x0010|0x0020|0x0008|0x0002,0,self.processName)
- #If the process is not found...
- if hprocess == 0 and self.injectAtStartup == 0:
- QtGui.QMessageBox.critical(self,'Python injector','Cannot find process.',QtGui.QMessageBox.Ok)
- return 0
- elif hprocess == 0 and self.injectAtStartup == 2:
- self.statusBar().showMessage('Waiting for {0}'.format(self.processName))
- while hprocess == 0:
- hprocess,pid = openByName(0x0400|0x0010|0x0020|0x0008|0x0002,0,self.processName)
- time.sleep(0.1) #Not to overload cpu
- kernel32 = windll.Kernel32 #Kernel 32 dll
- null = c_int(0) #A c null
- LEN_DLL = len(self.dllPath)+1 # Get the length of the DLL PATH
- #Get the address of loadlibrary function
- module = kernel32.GetModuleHandleA(b'kernel32.dll')
- lib_addr = kernel32.GetProcAddress( module,b'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
- a = kernel32.WriteProcessMemory (hprocess , str_addr , bytes(self.dllPath,'ascii') , 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
- for i in self.funcCall: #Function calling
- self.callFunction(hprocess,thread,i,self.funcCall[i][0],self.funcCall[i][1])
- if thread == 0:
- self.statusBar().showMessage('Injection failed!')
- return 0
- else:
- self.statusBar().showMessage('DLL successfully injected!')
- #Close the injector if needed.
- if thread != 0 and self.closeAfterInject == 2:
- self.processListWindow.hide() #The user might be an idiot and still have this window open...
- self.funcWindow.hide() #Again...
- self.close()
- def callFunction(self,hprocess,thread,name,arg,it): # !!! HERE IS THE CODE USED TO CALL A FUNCTION IN THE DLL !!!
- it = int(it)
- name = bytes(name,'ascii')
- try:
- arg = int(arg)
- except:
- arg = bytes(arg,'ascii')
- pass
- 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(bytes(self.dllPath,'ascii'))
- modfunc = kernel32.GetProcAddress ( findoff, name )
- offset = modfunc - findoff
- exitcode = exitcode.value + offset
- print(findoff,modfunc,kernel32.GetLastError())
- if type (arg )== int: arg = c_int( arg )
- if type (arg) == str: arg = c_char_p ( arg )
- for i in range(it):
- try:
- thread2 = kernel32.CreateRemoteThread ( hprocess ,null,null , # proc , sa, stacksize,
- c_long( exitcode ) ,arg,null ,null) # start_addr, args, flags,out[ID]
- except:
- pass
- if __name__ == '__main__':
- global app
- app = QtGui.QApplication(sys.argv)
- gui = Injector()
- sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment