从Python调用时C DLL破解 [英] C DLL crack when called from Python

查看:75
本文介绍了从Python调用时C DLL破解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用C / Python API嵌入Python解释器的DLL。如果调用DLL一次,则DLL可以正常工作,但是如果调用DLL两次,则代码会破解,并且我的程序会捕获内存错误。
调用DLL的C代码很简单,并且一次调用DLL函数(其中调用Python解释器),如果第二次调用(未在代码中)未注释该代码,则该代码会破裂,并且仅当 Numpy在Python代码中称为。

I've a DLL that embeds Python interpreter using the C/Python API. The DLL works fine if called one time, but if the DLL is called twice, the code cracks and my program catch memory error. The C code calling DLL is simple and the call to DLL function(Which calls Python interpreter) is done one time, if the second call(In the code) is not commented the code cracks and this happens only if "Numpy" is called in the Python code.

#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <dll_simples.h>

int main() {
double in[] = { 4,2,5,4,2 };
double out[5] = {};
double a = 0;
double b = 0;


simuser(a,b,in,out);
//simuser(a, b, in, out); IF NOT COMMENTED -> ERROR

return 0;
 }

我已在DLL中注释了Py_Finalize(),如建议此处,且此帖子此处从Py_Finalize()文档中确认如果某些扩展名可能无法正常使用它们的初始化例程不止一次被调用;如果应用程序多次调用Py_Initialize()和Py_Finalize(),则可能会发生这种情况。因此,我想知道为什么会发生这种情况,以及是否可以做最后一次对DLL的调用之外只调用 Py_Finalize()。

I've commented Py_Finalize() in the DLL as suggested here and this post here affirms that from Py_Finalize() docs"Some extensions may not work properly if their initialization routine is called more than once; this can happen if an application calls Py_Initialize() and Py_Finalize() more than once." So i'd like to know why this happens and if any other thing could be done except calls "Py_Finalize()" only one time in the last call to DLL.

推荐答案

列出 [Python 3.Docs ]:ctypes-Python的外部函数库。

Listing [Python 3.Docs]: ctypes - A foreign function library for Python.

dll00.h

#pragma once

#if defined(_WIN32)
#  if defined DLL0_EXPORTS
#    define DLL00_EXPORT_API __declspec(dllexport)
#  else
#    define DLL00_EXPORT_API __declspec(dllimport)
#  endif
#else
#  define DLL00_EXPORT_API
#endif


#if defined(__cplusplus)
extern "C" {
#endif

DLL00_EXPORT_API int dll00Func00(double t, double delta, unsigned int size, const double *pIn, double *pOut);

#if defined(__cplusplus)
}
#endif

dll00.c

#include <stdio.h>
#include "Python.h"
#define DLL0_EXPORTS
#include "dll00.h"

#define C_TAG "From C .dll"


int dll00Func00(double t, double delta, unsigned int size, const double *pIn, double *pOut) {
    int res = 0;
    printf("%s: in function\n", C_TAG);
    const int isInit = Py_IsInitialized();
    // Modify array calling Python functions
    if (!isInit) {
        printf("%s: initializing Python interpreter\n", C_TAG);
        Py_Initialize();
    }
    res = PyRun_SimpleString("print(\"From Python (within C .dll): test\")");
    for (unsigned  int i = 0; i < size; i++) {
        pOut[i] = pIn[i] * t + delta;
    }
    if (!isInit) {
        printf("%s: uninitializing Python interpreter\n", C_TAG);
        Py_Finalize();
    }
    return 0;
}

main00.c

#include <stdio.h>

#include "dll00.h"
#define SIZE 4


int main() {
    int res = 0;
    double in[SIZE] = { 10.0, 11.0, 12.0, 13.0 };
    double out[SIZE] = { 0 };
    res = dll00Func00(2, 0.5, SIZE, in, out);
    printf("Output array:\n");
    for (unsigned int i = 0; i < SIZE; i++) {
        printf("%.03f ", out[i]);
    }
    printf("\n");
    return 0;
}

code00.py

#!/usr/bin/env python

import sys
import ctypes as ct


DLL_NAME = "./dll00.dll"


def main(*argv):
    DblPtr = ct.POINTER(ct.c_double)
    size = 5
    DblArr = ct.c_double * size

    dll00 = ct.PyDLL(DLL_NAME)
    dll00Func00 = dll00.dll00Func00
    dll00Func00.argtypes = (ct.c_double, ct.c_double, ct.c_uint, DblPtr, DblPtr)
    dll00Func00.restype = ct.c_int

    in_arr = DblArr(*range(size))
    out_arr = DblArr()
    print("Output array:")
    for i in range(size):
        print("{:.3f}".format(out_arr[i]), end=" ")
    print("\n")
    res = dll00Func00(2, 2.5, size, in_arr, out_arr)
    print("Output array:")
    for i in range(size):
        print("{:.3f}".format(out_arr[i]), end=" ")
    print()



if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(*sys.argv[1:])
    print("\nDone.")

注释


  • Python ,使用 ctypes.PyDLL 时(间接)调用 Python API 函数

  • .dll 中,使用 [Python 3.Docs]:初始化,完成和线程- int Py_IsInitialized ()


    • 作为补充,在 Py_Initialize 的情况下,不需要 if 测试,因为 Py_Initialize 仅在以下情况下返回:解释器已经初始化(因此为了一致性起见,我把它留在了这里),但 Py_Finalize 却需要它,因为不想在仍处于 Python 中的情况下取消初始化解释器。
      因此 Py_Initialize / Py_Finalize 对不适用于引用计数(每个 Py_Initialize 调用都需要一个 Py_Finalize 一个)

    • In Python, use ctypes.PyDLL as you're (indirectly) calling Python API functions
    • In the .dll, use [Python 3.Docs]: Initialization, Finalization, and Threads - int Py_IsInitialized()
      • As a side note, the if test is not needed in Py_Initialize's case as Py_Initialize simply returns if the interpreter is already initialized (so I left it there just for consistency), but it is needed for Py_Finalize as one wouldn't want to uninitialize the interpreter while still in Python.
        So Py_Initialize / Py_Finalize pair doesn't work on "reference count" (every Py_Initialize call requires an Py_Finalize one)

      在窗口中调用 Py_Initialize / Py_Finalize 函数,似乎有些矫kill过正(如果多次调用该函数)。我要在 .dll 中执行2个包装函数,然后调用:

      Calling Py_Initialize / Py_Finalize in the function, seems like an overkill (if the function is being called multiple times). I'd do 2 wrapper functions in the .dll and call:


      • 在开始处一个

      • 最后一个对方

      / p>


    • of the (C) program

      输出


      e:\Work\Dev\StackOverflow\q059937552>sopr.bat
      *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
      
      [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2017\VC\Auxiliary\Build\vcvarsall.bat" x64
      **********************************************************************
      ** Visual Studio 2017 Developer Command Prompt v15.9.19
      ** Copyright (c) 2017 Microsoft Corporation
      **********************************************************************
      [vcvarsall.bat] Environment initialized for: 'x64'
      
      [prompt]> dir /b
      code00.py
      dll00.c
      dll00.h
      main00.c
      
      [prompt]> cl /nologo /MD /DDLL /I"c:\Install\pc064\Python\Python\03.07.06\include" dll00.c  /link /NOLOGO /DLL /OUT:dll00.dll /LIBPATH:"c:\Install\pc064\Python\Python\03.07.06\libs"
      dll00.c
         Creating library dll00.lib and object dll00.exp
      
      [prompt]> cl /nologo /MD /W0 main00.c  /link /NOLOGO /OUT:main00_064.exe dll00.lib
      main00.c
      
      [prompt]> dir /b
      code00.py
      dll00.c
      dll00.dll
      dll00.exp
      dll00.h
      dll00.lib
      dll00.obj
      main00.c
      main00.obj
      main00_064.exe
      
      [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py
      Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32
      
      Output array:
      0.000 0.000 0.000 0.000 0.000
      
      From C .dll: in function
      From Python (within C .dll): test
      Output array:
      2.500 4.500 6.500 8.500 10.500
      
      Done.
      
      [prompt]> set PATH=%PATH%;c:\Install\pc064\Python\Python\03.07.06
      
      [prompt]> main00_064.exe
      From C .dll: in function
      From C .dll: initializing Python interpreter
      From Python (within C .dll): test
      From C .dll: uninitializing Python interpreter
      Output array:
      20.500 22.500 24.500 26.500
      


      这篇关于从Python调用时C DLL破解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆