dberube4

PyInject 3.x

Aug 16th, 2012
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.90 KB | None | 0 0
  1. from ctypes import *
  2. from PyQt4 import QtCore,QtGui
  3. import sys,time
  4.  
  5. #Shortening names
  6. button = QtGui.QPushButton
  7. label = QtGui.QLabel
  8. textbox = QtGui.QLineEdit
  9. checkbox = QtGui.QCheckBox
  10. listbox = QtGui.QListWidget
  11.  
  12. #This function roughly equals "process.GetProcessesByName(name)" (in vb) translated into python. It return the procees handle and the process pid (handle,PID).
  13. #It only work for 32 bits process!
  14. #For more informations see : http://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx
  15. def openByName(access,handle,name):
  16.         kernel32 = windll.kernel32
  17.         psapi = windll.psapi
  18.         arr = c_ulong * 256
  19.         lpidProcess = arr()
  20.         cbNeeded = c_ulong()
  21.         hModule = c_ulong()
  22.         count =  c_ulong()
  23.         modname = c_buffer(30)
  24.        
  25.         psapi.EnumProcesses(byref(lpidProcess),sizeof(lpidProcess),byref(cbNeeded))
  26.        
  27.         for pid in lpidProcess:
  28.             hProcess = kernel32.OpenProcess(0x0400|0x0010,False, pid)
  29.            
  30.             if hProcess:
  31.                 psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count))
  32.                 psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname))
  33.                
  34.                 try:
  35.                     a  = str(modname.value,'utf8')
  36.                 except:
  37.                     a= None
  38.                        
  39.                 if a != name:
  40.                     for i in range(modname._length_):
  41.                         modname[i]=b'\x00'
  42.                     kernel32.CloseHandle(hProcess)
  43.                 else:
  44.                     kernel32.CloseHandle(hProcess)
  45.                     handle = kernel32.OpenProcess(access,handle,pid)
  46.                     return handle,pid
  47.                    
  48.         return 0,0
  49.  
  50. #This is the same function as above but edited to return a list of process
  51. def listProcess():
  52.         processList = []
  53.         kernel32 = windll.kernel32
  54.         psapi = windll.psapi
  55.         arr = c_ulong * 256
  56.         lpidProcess = arr()
  57.         cbNeeded = c_ulong()
  58.         hModule = c_ulong()
  59.         count =  c_ulong()
  60.         modname = c_buffer(30)
  61.        
  62.         psapi.EnumProcesses(byref(lpidProcess),sizeof(lpidProcess),byref(cbNeeded))
  63.        
  64.         for pid in lpidProcess:
  65.             hProcess = kernel32.OpenProcess(0x0400|0x0010,False, pid)
  66.            
  67.             if hProcess:
  68.                 psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count))
  69.                 psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname))
  70.                 a = ''
  71.                
  72.                 try:
  73.                     a  = str(modname.value,'utf8')
  74.                     processList.append(a)
  75.                 except:
  76.                     pass
  77.                
  78.                 for i in range(modname._length_):
  79.                     modname[i]=b'\x00'
  80.                
  81.                 kernel32.CloseHandle(hProcess)
  82.        
  83.         #l1 is not enough:
  84.         for i in range (10):
  85.             for i in processList:
  86.                 if not '.exe' in i:
  87.                     processList.remove(i)
  88.         return processList
  89.  
  90.  
  91. class Injector(QtGui.QMainWindow):
  92.    
  93.     def __init__(self):
  94.         super(Injector,self).__init__() #This line roughly make "self" = QtGui.QMainWindow
  95.        
  96.         #Global variables of the program are inited here
  97.         self.dllPath = ''
  98.         self.processName = ''
  99.         self.injectAtStartup = 0
  100.         self.closeAfterInject = 0
  101.         self.funcCall = {}
  102.        
  103.         #This start the function who init the main window and other windows.
  104.         self.initMain()
  105.         self.initProcessList()
  106.         self.initFuncList()
  107.        
  108.     def initMain(self): #Main window is inited here
  109.        
  110.         def actions(*argv): #Main window actions are handled here (*argv will hold extra data sent by the widget)
  111.             sender = self.sender() #This get the last widget who activated this functions.
  112.                
  113.             if sender == self.getProcessBtn:
  114.                 self.processListWindow.show() # See "def initProcessList(self)"
  115.            
  116.             if sender == self.optionsBtn:
  117.                 self.funcWindow.show()
  118.                
  119.             if sender == self.getDllBtn:
  120.                 response = QtGui.QFileDialog.getOpenFileName(self,'Choose dll',filter = '*.dll')
  121.                 if response != '': #It return a null string if the user select cancel
  122.                     self.dllTxtBox.setText(response)
  123.                
  124.             if sender == self.injectAtStartupCB:
  125.                 self.injectAtStartup = argv[0] #Note: argv[0] is the current Qt.CheckState of the checkbox (0 if unchecked,2 if checked).
  126.                
  127.             if sender == self.closeAfterInjectCB:
  128.                         self.closeAfterInject = argv[0] #Note: argv[0] is the current Qt.CheckState of the checkbox (0 if unchecked,2 if checked).
  129.                
  130.             if sender == self.injectBtn:
  131.                 self.dllPath = str(self.dllTxtBox.text())
  132.                 self.processName = str(self.processTxtBox.text())
  133.                 self.inject()
  134.        
  135.         def initWidgets(): #Main window widgets are inited here.
  136.                
  137.                 #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()).
  138.                
  139.                 processLbl = label('Process:',self);processLbl.move(10,20)
  140.                 dllLbl = label('Dll:',self);dllLbl.move(10,80)
  141.                
  142.                 self.injectBtn = button('Inject!',self);self.injectBtn.setGeometry(190,165,150,30);self.injectBtn.clicked.connect(actions)
  143.                 self.optionsBtn = button('Options',self);self.optionsBtn.setGeometry(190,125,150,30);self.optionsBtn.clicked.connect(actions)
  144.                 self.getProcessBtn = button('...',self);self.getProcessBtn.setGeometry(310,30,30,20);self.getProcessBtn.clicked.connect(actions)
  145.                 self.getDllBtn = button('...',self);self.getDllBtn.setGeometry(310,90,30,20);self.getDllBtn.clicked.connect(actions)
  146.                 self.injectAtStartupCB = checkbox('Inject at startup',self);self.injectAtStartupCB.setGeometry(10,140,160,17);self.injectAtStartupCB.stateChanged.connect(actions)
  147.                 self.injectAtStartupCB.setToolTip('Check this if the process is not yet started')
  148.                 self.closeAfterInjectCB = checkbox('Close after inject',self);self.closeAfterInjectCB.setGeometry(10,170,160,17);self.closeAfterInjectCB.stateChanged.connect(actions)
  149.                 self.processTxtBox = textbox('Process.exe',self);self.processTxtBox.setGeometry(80,20,220,30)
  150.                 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.
  151.        
  152.         try:
  153.             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.
  154.         except:
  155.             QtGui.QMessageBox.warning(self,'Python injector','Cannot find style script... too bad for you.',QtGui.QMessageBox.Ok)
  156.         #The main window properties are inited here
  157.         self.setFixedSize(350,225)
  158.         self.setFont(self.font) #Note font are defined in style script
  159.         self.setWindowTitle('PyInject - Python injector')
  160.         self.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowCloseButtonHint)
  161.         self.statusBar().showMessage('Ready')
  162.         initWidgets()
  163.         self.show()
  164.  
  165.     def initProcessList(self): #Another window
  166.        
  167.         def actions(*argv): #Main window actions are handled here (*argv will hold extra data sent by the widget)
  168.             sender = self.sender() #This get the last widget who activated this functions.
  169.            
  170.             if sender == self.chooseProcess:
  171.                 try: #Catch the error when the user click done but has selected nothing.
  172.                         self.processTxtBox.setText(self.processList.item(self.processList.currentRow()).text())
  173.                 except AttributeError:
  174.                         pass
  175.                 self.processListWindow.hide()
  176.                
  177.             if sender == self.refreshBtn:
  178.                 self.processList.clear()
  179.                 self.processList.addItems(listProcess())
  180.                
  181.         def initWidgets(wind):#Main window widgets are inited here.
  182.             self.processList = listbox(wind);self.processList.setGeometry(5,5,190,210);self.processList.setFont(self.smallFont) #Note : fonts are defined in style script.
  183.             self.chooseProcess = button('Done',wind);self.chooseProcess.setGeometry(5,217,90,30);self.chooseProcess.clicked.connect(actions)
  184.             self.refreshBtn = button('Refresh',wind);self.refreshBtn.setGeometry(105,217,90,30);self.refreshBtn.clicked.connect(actions)
  185.  
  186.  
  187.         #Adding a child window to the main window. THE NEW WIDGET MUST NOT BE PARENTED!!!!!
  188.         self.processListWindow = QtGui.QWidget()
  189.         self.processListWindow.setWindowTitle('Choose a process')
  190.         self.processListWindow.setFixedSize(200,250)
  191.         self.processListWindow.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowCloseButtonHint)
  192.         #self.processListWindow.show() is omitted because this window must be hidden when the program starts.
  193.         initWidgets(self.processListWindow)
  194.  
  195.     def initFuncList(self):#Another window
  196.        
  197.         def actions(*argv):
  198.             sender = self.sender()
  199.            
  200.             if sender == self.noneArg:
  201.                 if argv[0]:
  202.                     self.funcArg.setEnabled(False)
  203.                 else:
  204.                     self.funcArg.setEnabled(True)
  205.            
  206.             if sender == self.addBtn:
  207.                 if self.funcName.text() != '' and self.noneArg.checkState() == 2:
  208.                    
  209.                     aList = self.funcCallList.findItems('{0}::{1}'.format(self.funcName.text(),None),QtCore.Qt.MatchStartsWith)
  210.                     if aList == []:
  211.                         self.funcCallList.addItem('{0}::{1}::1'.format(self.funcName.text(),None))
  212.                     else:
  213.                         num = int(str(aList[0].text()).split('::')[2])+1
  214.                         aList[0].setText('{0}::{1}::{2}'.format(self.funcName.text(),None,num))
  215.                    
  216.                 elif self.funcName.text() != '' and self.funcArg.text() != '':
  217.                    
  218.                     aList = self.funcCallList.findItems('{0}::{1}'.format(self.funcName.text(),self.funcArg.text()),QtCore.Qt.MatchStartsWith)
  219.                     if  aList == []:
  220.                         self.funcCallList.addItem('{0}::{1}::1'.format(self.funcName.text(),self.funcArg.text()))
  221.                     else:
  222.                         num = int(str(aList[0].text()).split('::')[2])+1
  223.                         aList[0].setText('{0}::{1}::{2}'.format(self.funcName.text(),self.funcArg.text(),num))
  224.                    
  225.                 else:
  226.                     QtGui.QMessageBox.warning(self.funcWindow,'Python injector','The function need a title and 1 argument.',QtGui.QMessageBox.Ok)
  227.                    
  228.             if sender == self.remBtn:
  229.                 if self.funcCallList.currentRow() != -1:
  230.                     self.funcCallList.takeItem(self.funcCallList.currentRow())
  231.                 else:
  232.                     QtGui.QMessageBox.warning(self.funcWindow,'Python injector','Select a function first!',QtGui.QMessageBox.Ok)    
  233.            
  234.             if sender == self.clrBtn:
  235.                 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)
  236.                 if resp == QtGui.QMessageBox.Yes:
  237.                     self.funcCallList.clear()
  238.            
  239.             if sender == self.okBtn:
  240.                 self.funcCall = {}
  241.                 for i in range(self.funcCallList.count()):
  242.                     text = self.funcCallList.item(i).text().split('::')
  243.                     self.funcCall[str(text[0])] = [str(text[1]),str(text[2])]
  244.                 QtGui.QMessageBox.information(self.funcWindow,'Python injector','{0} functions call were added.'.format(self.funcCallList.count()),QtGui.QMessageBox.Ok)
  245.                 self.funcWindow.hide()
  246.        
  247.         def initWidgets(wind):
  248.                
  249.             self.funcName = textbox('Function name here',wind);self.funcName.setGeometry(10,10,200,25)
  250.             self.funcArg = textbox('Function argument',wind);self.funcArg.setGeometry(230,10,150,25)
  251.             self.noneArg = checkbox('None',wind);self.noneArg.setGeometry(385,10,150,25);self.noneArg.stateChanged.connect(actions)
  252.             self.addBtn = button('Add',wind);self.addBtn.setGeometry(345,160,100,25);self.addBtn.clicked.connect(actions)
  253.             self.remBtn = button('Remove',wind);self.remBtn.setGeometry(235,160,100,25);self.remBtn.clicked.connect(actions)
  254.             self.clrBtn = button('Clear',wind);self.clrBtn.setGeometry(125,160,100,25);self.clrBtn.clicked.connect(actions)
  255.             self.okBtn = button('OK',wind);self.okBtn.setGeometry(15,160,100,25);self.okBtn.clicked.connect(actions)
  256.             self.funcCallList = listbox(wind);self.funcCallList.setGeometry(10,45,430,108)
  257.             self.funcCallList.setToolTip("Functions call are represented here\n ([Function name]::[Argument]::[Number of time to send]) .")
  258.  
  259.         #Adding a child window to the main window. THE NEW WIDGET MUST NOT BE PARENTED!!!!!
  260.         self.funcWindow = QtGui.QWidget()
  261.         self.funcWindow.setFont(self.smallFont)
  262.         self.funcWindow.setWindowTitle('Functions to call')
  263.         self.funcWindow.setFixedSize(450,190)
  264.         self.funcWindow.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowCloseButtonHint)
  265.         #self.funcWindow.show() is omitted because this window must be hidden when the program starts.
  266.         initWidgets(self.funcWindow)
  267.  
  268.     def inject(self): # !!! ACTUAL INJECTOR CODE IS IN HERE !!!
  269.        
  270.         #Check is dll path is valid
  271.         try:
  272.             open(self.dllPath,'rb')
  273.         except:
  274.             QtGui.QMessageBox.critical(self,'Python injector','Cannot find dll.',QtGui.QMessageBox.Ok)
  275.             return 0
  276.        
  277.         #Try to open a process
  278.         hprocess,pid = openByName(0x0400|0x0010|0x0020|0x0008|0x0002,0,self.processName)
  279.         #If the process is not found...
  280.         if hprocess == 0 and self.injectAtStartup == 0:
  281.             QtGui.QMessageBox.critical(self,'Python injector','Cannot find process.',QtGui.QMessageBox.Ok)
  282.             return 0
  283.         elif hprocess == 0 and self.injectAtStartup == 2:
  284.             self.statusBar().showMessage('Waiting for {0}'.format(self.processName))
  285.             while hprocess == 0:
  286.                 hprocess,pid = openByName(0x0400|0x0010|0x0020|0x0008|0x0002,0,self.processName)
  287.                 time.sleep(0.1) #Not to overload cpu
  288.        
  289.         kernel32 = windll.Kernel32 #Kernel 32 dll
  290.         null = c_int(0) #A c null
  291.         LEN_DLL = len(self.dllPath)+1 # Get the length of the DLL PATH
  292.        
  293.         #Get the address of loadlibrary function
  294.        
  295.         module = kernel32.GetModuleHandleA(b'kernel32.dll')
  296.         lib_addr = kernel32.GetProcAddress( module,b'LoadLibraryA')
  297.        
  298.         # get some read/writable mem in target proc so target can read some data we give it
  299.         str_addr = kernel32.VirtualAllocEx ( hprocess,null,c_long(LEN_DLL),0x00001000|0x00002000,4 )
  300.  
  301.         # write the dllname we want to run to the remote memory
  302.         a = kernel32.WriteProcessMemory (hprocess , str_addr , bytes(self.dllPath,'ascii') , c_long(LEN_DLL) , null)
  303.        
  304.         #Creating Remote Thread to load our DLL
  305.         thread = kernel32.CreateRemoteThread ( hprocess ,null,null ,
  306.                                                c_long( lib_addr ) ,c_long( str_addr) , null,null)
  307.         time.sleep(0.1) #To ensure that everything is correct
  308.        
  309.         for i in self.funcCall:  #Function calling
  310.             self.callFunction(hprocess,thread,i,self.funcCall[i][0],self.funcCall[i][1])
  311.        
  312.         if thread == 0:
  313.             self.statusBar().showMessage('Injection failed!')
  314.             return 0
  315.         else:
  316.              self.statusBar().showMessage('DLL successfully injected!')
  317.                
  318.         #Close the injector if needed.
  319.         if thread != 0 and self.closeAfterInject == 2:
  320.             self.processListWindow.hide() #The user might be an idiot and still have this window open...
  321.             self.funcWindow.hide() #Again...
  322.             self.close()
  323.        
  324.     def callFunction(self,hprocess,thread,name,arg,it): # !!! HERE IS THE CODE USED TO CALL A FUNCTION IN THE DLL !!!
  325.        
  326.         it = int(it)
  327.         name = bytes(name,'ascii')
  328.         try:
  329.             arg = int(arg)
  330.         except:
  331.             arg = bytes(arg,'ascii')
  332.             pass
  333.        
  334.         kernel32 = windll.Kernel32 #Kernel 32 dll
  335.         null = c_int(0) #A c null
  336.         exitcode = c_int()
  337.        
  338.         a = kernel32.GetExitCodeThread( thread,byref(exitcode))
  339.         findoff =  kernel32.LoadLibraryA(bytes(self.dllPath,'ascii'))
  340.         modfunc = kernel32.GetProcAddress ( findoff, name  )
  341.         offset = modfunc - findoff
  342.         exitcode = exitcode.value + offset
  343.         print(findoff,modfunc,kernel32.GetLastError())
  344.         if type (arg )== int: arg = c_int( arg )
  345.         if type (arg) == str: arg = c_char_p ( arg )
  346.         for i in range(it):
  347.                 try:
  348.                      thread2 = kernel32.CreateRemoteThread ( hprocess ,null,null , # proc , sa, stacksize,
  349.                                                              c_long( exitcode ) ,arg,null ,null) # start_addr, args, flags,out[ID]
  350.                 except:
  351.                      pass
  352.  
  353. if __name__ == '__main__':
  354.     global app
  355.     app = QtGui.QApplication(sys.argv)
  356.     gui = Injector()
  357.     sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment