[Release] How to create and use a .pyd file for metin2 client

04/20/2013 21:31 lollo_9_1#1
Intro
What is a .pyd file? A .pyd file is only a .dll (renamed in .pyd) that contains the necessary information to use it as a python module.

PS. The "main" function of this lib "_mydaemon" is "init_mydaemon", if you want to change the name to (es.) "smthelse" the relative "main" function should be "initsmthelse".

There are 2 ways to build a .pyd on windows:
  • distutils (there are more issues with python22, vc++6 and another distutils's settings on recent windows OSes and current compilers=bad way)
  • using directly a compiler such as vc++ (tested on vs2010)

The relative ways
I said there are 2 ways, no?
  • The first way is the worst but if you don't care about this, here how to do it:
    -Create a .bat with this inside: (if you want to use another compiler other than vc++6 you have to edit the relative details inside python22\lib\distutils\msvccompiler.py; NB. you can also use mingw! NB2. for this .bat I'm using vs100!)
    Code:
    call "%vs100comntools%vsvars32.bat"
    python .\_mydaemon\setup.py build -cmsvc --force
    pause
    And, into the relative .py:
    Code:
    import distutils
    from distutils.core import setup, Extension
    setup(name = '_mydaemon',
    		version = '1.8',
    		author = 'martysama0134',
    		description = 'MyDaemon Package',
    		url = 'http://docs.python.org/extending/building',
    		ext_modules = [Extension('_mydaemon', sources = [r'c:\Users\blablabla\_mydaemon\_mydaemon.cpp'],)]
    )
    So, run the .bat and hope that everything will go well.
    (you'll find the source of _mydaemon.cpp below)
  • Second way (tested on vs2010)
    Create a project with this 2 files:
    Code:
    // _mydaemon.h
    #pragma once
    //# pyd required BEGIN
    #include <Python.h>//<stdio.h>, <string.h>, <errno.h>, <stdlib.h>
    //# pyd required END
    //c++module
    #include <iostream>//std::cin/cout
    #include <windows.h>
    #include <tlhelp32.h>//module32 funcs
    #include <tchar.h>//unicode set
    //#include <stdio.h>
    Code:
    // _mydaemon.cpp
    #include "_mydaemon.h"
    static PyObject* MyDaemonError;
    
    /*START CODE*/
    static PyObject* MyDaemon_DllView2(PyObject *self, PyObject *args)
    {
    	DWORD dwPID;
    	if(!PyArg_ParseTuple(args, "i", &dwPID))
    		return NULL;
    
    	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
    	MODULEENTRY32 me32;
    	// Take a snapshot of all modules in the specified process.
    	hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
    	if(hModuleSnap == INVALID_HANDLE_VALUE)
    	{
    		return Py_BuildValue("i", 0); // CreateToolhelp32Snapshot (of modules)
    	}
    	// Set the size of the structure before using it.
    	me32.dwSize = sizeof(MODULEENTRY32);
    	// Retrieve information about the first module,
    	// and exit if unsuccessful
    	if(!Module32First(hModuleSnap, &me32))
    	{
    		CloseHandle(hModuleSnap);
    		return Py_BuildValue("i", 0);//Module32First
    	}
    	// Now walk the module list of the process,
    	// and display information about each module
    	int tuplemain_index = 0;
    	do{tuplemain_index++;}while(Module32Next(hModuleSnap, &me32));
    	PyObject *DllTupleMain = PyTuple_New(tuplemain_index);
    	PyObject *DllTupleChild;
    
    	Module32First(hModuleSnap, &me32);
    	tuplemain_index = 0;
    	do
    	{
    		DllTupleChild = Py_BuildValue("(uuii)", me32.szModule, me32.szExePath, (DWORD) me32.modBaseAddr, me32.modBaseSize);
    		PyTuple_SetItem(DllTupleMain, tuplemain_index, DllTupleChild);
    		tuplemain_index++;
    	}while(Module32Next(hModuleSnap, &me32));
    	CloseHandle(hModuleSnap);
    	return DllTupleMain;
    }
    static PyObject* MyDaemon_System(PyObject *self, PyObject *args)
    {
    	//ps. os.popen is better
    	char* command;
    	int sts;
    	if(!PyArg_ParseTuple(args, "s", &command))
    		return NULL;
    	sts = system(command);
    	return Py_BuildValue("i", sts);
    }
    static PyObject* MyDaemon_LoadLib(PyObject *self, PyObject *args)
    {
    	char* libname;
    	if(!PyArg_ParseTuple(args, "s", &libname))
    		return NULL;
    	//std::cout << libname << std::endl;
    	HINSTANCE myH = LoadLibraryA(libname);
    	return Py_BuildValue("i", myH != NULL);
    }
    
    static PyObject* MyDaemon_TaskList(PyObject *self, PyObject *args)
    {
    	HANDLE hProcessSnap;
    	HANDLE hProcess;
    	PROCESSENTRY32 pe32;
    	DWORD dwPriorityClass;
    	hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    	if(hProcessSnap == INVALID_HANDLE_VALUE)
    	{
    		return Py_BuildValue("i", 0); // CreateToolhelp32Snapshot (of processes)
    	}
    	// Set the size of the structure before using it.
    	pe32.dwSize = sizeof(PROCESSENTRY32);
    
    	// Retrieve information about the first process,
    	// and exit if unsuccessful
    	if(!Process32First(hProcessSnap, &pe32))
    	{
    		CloseHandle(hProcessSnap);// clean the snapshot object
    		return Py_BuildValue("i", 0); // Process32First
    	}
    	
    	int tuplemain_index = 0;
    	do{tuplemain_index++;}while(Process32Next(hProcessSnap, &pe32));
    	PyObject *DllTupleMain = PyTuple_New(tuplemain_index);
    	PyObject *DllTupleChild;
    
    	Process32First(hProcessSnap, &pe32);
    	tuplemain_index = 0;
    	do
    	{
    		dwPriorityClass = 0;
    		// Retrieve the priority class.
    		hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
    		//if(hProcess == NULL){}
    		//else
    		if(hProcess != NULL)
    		{
    			dwPriorityClass = GetPriorityClass(hProcess);
    			CloseHandle(hProcess);
    		}
    		DllTupleChild = Py_BuildValue("(uiiiii)",
    			pe32.szExeFile, pe32.th32ProcessID, pe32.cntThreads, pe32.th32ParentProcessID, pe32.pcPriClassBase, dwPriorityClass);
    		PyTuple_SetItem(DllTupleMain, tuplemain_index, DllTupleChild);
    		tuplemain_index++;
    	} while(Process32Next(hProcessSnap, &pe32));
    
    	CloseHandle(hProcessSnap);
    	return DllTupleMain;
    }
    
    /*METHODS_LIST*/
    static PyMethodDef MyDaemonMethods[] = {
    	{"dllview2",  MyDaemon_DllView2, METH_VARARGS, "DllView in tuple return."},
    	{"loadlib",  MyDaemon_LoadLib, METH_VARARGS, "Load a dll in memory."},
    	{"system",  MyDaemon_System, METH_VARARGS, "Execute a shell command."},
    	{"tasklist",  MyDaemon_TaskList, METH_VARARGS, "Show all active pc-process."},
    	{NULL, NULL, 0, NULL}
    };
    /*INIT*/
    DL_EXPORT(void) init_mydaemon(void)
    {
    	PyObject *m, *d;
    	m = Py_InitModule("_mydaemon", MyDaemonMethods);
    	MyDaemonError = PyErr_NewException("_mydaemon.error", NULL, NULL);
    	d = PyModule_GetDict(m);
    	PyDict_SetItemString(d, "error", MyDaemonError);
    }
    PS. I'm using unicode charset in my vs2010 project, so, if you want to use NoSet char you must remember to change the actual argument "u" to "s" of the Py_BuildValue function!

    Now, you have to add this inside the (Project) Properties -> Configuration Properties -> Linker -> Command Line -> Additional Options:
    Code:
     /export:init_mydaemon

    Don't forget to add the python22 include path here:
    (Project) Properties -> Configuration Properties -> C/C++ -> General -> Additional Include Directories
    (you must install python22 on your os or, just download the python2.2.3 sources and compile them with vc++6 for the relative .lib files to include)

Now, build the project and you'll get the pyd!
Rename your .dll to .pyd and move it into the client\lib path (info [Only registered and activated users can see links. Click Here To Register...] [Only registered and activated users can see links. Click Here To Register...])

To use this "new module" in python you just need to write something like this:
Code:
import _mydaemon
#you can also do this:
import _mydaemon as myd
#show me my module namespaces!
##print dir(myd)
#now it's time to test my defs!
_mydaemon.loadlib("mylib.dll")#load this library in memory
#
import os
dllloadedinmyclientbin=_mydaemon.dllview(os.get_pid())#tuple return
##for dllsnap in dllloadedinmyclientbin:
##	print ", ".join([str(i) for i in dllsnap])
#
tasklist=_mydaemon.tasklist()
#
_mydaemon.system(r"echo this >> %userprofile%\desktop\this.txt")
In other words, my module contains 4 functions as example:
  • _mydaemon.dllview2(pid) // it returns a tuple of all the dll injected into the pid process
  • _mydaemon.loadlib(libname) // it loads libname in memory
  • _mydaemon.tasklist() // it returns a tuple containing all the active processes on your computer
  • _mydaemon.system(cmd) // it invokes the shell to execute cmd

Other
  • I used this example to make dllview&tasklist defs: [Only registered and activated users can see links. Click Here To Register...]
  • You can read the relative python documentation [Only registered and activated users can see links. Click Here To Register...] (this looks even better: [Only registered and activated users can see links. Click Here To Register...])
  • You should remember that this is only an example code, if you want to load a library or to show dlls/processes in another way it's your choice
04/20/2013 21:33 .RazerX#2
I Might Not Understand Anything Of These... But Whatever .. Thanks
04/20/2013 21:37 DexterSK#3
gj.
04/20/2013 23:39 lollo_9_1#4
Quote:
Originally Posted by kwiatmix View Post
[Only registered and activated users can see links. Click Here To Register...]
My problem
Are u trying to build a .exe instead of a .dll? (dll -> empty project)

Below the example project (vs2010): (for dummies)
10/19/2014 02:18 ryngo#5
A method to decompile a .pyd file exist??? in windows 7
10/19/2014 04:11 lollo_9_1#6
Quote:
Originally Posted by ryngo View Post
A method to decompile a .pyd file exist??? in windows 7
A .pyd is a simple .dll written in c/c++ and used as python module.
You can't decompile it. You can only disasseble it using IDA or programs like that.
NB: It's completely different from the .pyc/pyo formats, which are only byte-code instructions for the python interpreter.
10/21/2014 22:44 ryngo#7
And exist a tutorial "how to" explicit, because i search an entiere google/youtube and nothing. I dont know extacly how to use IDA but i leran fast If i watch.