摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中。但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就提出了一种把通过FILE*来访问内存的需求,下文是针对这个需求的几个方面的尝试及其结论。

以下尝试的前提是:Win7 + VS2010.

在vc中,FILE其实就是_iobuf,定义如下:

  1. struct _iobuf {
  2. char *_ptr; //文件输入的下一个位置
  3. int _cnt; //当前缓冲区的相对位置
  4. char *_base; //指基础位置(应该是文件的其始位置)
  5. int _flag; //文件标志
  6. int _file; //文件的有效性验证
  7. int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
  8. int _bufsiz; //文件的大小
  9. char *_tmpfname;//临时文件名
  10. };
  11. typedef struct _iobuf FILE;

本文尝试了以下两种方法:

一、如何通过FILE*访问内存块,尝试1:_open_osfhandle(), 失败

其思路就是将解密之后的内容放入到内存映射文件中(实际上是一个句柄),然后把内存映射文件转换为FILE*,

网上有一个这方面的帖子(如何通过FILE*操作内存文件?http://www.cppblog.com/mythma/archive/2005/10/15/681.html)。这个想法的核心是通过将一个内存映射文件的windows句柄(HANDLE)转换为一个标准C的FILE*,有一个这方面的函数(_open_osfhandle)但是这个方法之对普通文件的HANDLE有效,对内存映射文件的HANDLE是无效的.

下面是实验代码:

  1. #include "stdafx.h"
  2. #include "TestMemFile.h"
  3. #include <io.h>
  4. #include <fcntl.h>
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #endif
  8.  
  9. // 唯一的应用程序对象
  10.  
  11. CWinApp theApp;
  12. using namespace std;
  13.  
  14. HANDLE CreateMMapFileFromMem()
  15. {
  16. TCHAR* MF_NAME = _T("MF_FILE_NAME_TEST");
  17. int MF_SIZE = *;
  18. std::cout<<"create a mem map file from mem"<<std::endl;
  19. return CreateFileMapping(INVALID_HANDLE_VALUE,
  20. NULL, PAGE_READWRITE, ,
  21. MF_SIZE, MF_NAME);
  22. }
  23.  
  24. HANDLE CreateMMapFileFromFile()
  25. {
  26. std::cout<<"create a normal file"<<std::endl;
  27. //这里我事先已经在D盘创建好文件,并且内容是字符 aaa
  28. HANDLE hFile = CreateFile(L"D:\\TestMemMapFile.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL, NULL);
  29. return hFile;
  30. }
  31.  
  32. /*一个用于创建内存映射文件的函数指针*/
  33.  
  34. typedef HANDLE (*CREATE_FILE_HANDLE)(void);
  35.  
  36. void TestConvertHANDLEToFILEPtr(CREATE_FILE_HANDLE lpCreateFile)
  37. {
  38. HANDLE hFile = lpCreateFile();
  39. if(hFile == nullptr)
  40. {
  41. std::cout<<"create file failed."<<std::endl;
  42. return;
  43. }
  44. int hfd = _open_osfhandle((intptr_t)hFile, _O_RDONLY);
  45.  
  46. if(hfd == -)
  47. {
  48. std::cout<<"convert File HANDLE to FILE* failed."<<std::endl;
  49. CloseHandle(hFile);
  50. return;
  51. }
  52. std::cout<<"convert File HANDLE to FILE* success. "<<std::endl;
  53. FILE* fd = _fdopen(hfd,"r");
  54. char c = getc(fd);
  55. std::cout<<"use getc(fd) to read a char from converted fd success, the char value is :" << c << std::endl;
  56. fclose((FILE*)fd);
  57. }
  58.  
  59. int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
  60.  
  61. {
  62. int nRetCode = ;
  63. HMODULE hModule = ::GetModuleHandle(NULL);
  64. if (hModule != NULL)
  65. {
  66. // 初始化 MFC 并在失败时显示错误
  67. if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), ))
  68. {
  69. // TODO: 更改错误代码以符合您的需要
  70. _tprintf(_T("错误: MFC 初始化失败\n"));
  71. nRetCode = ;
  72. }
  73. else
  74. {
  75. // TODO: 在此处为应用程序的行为编写代码。
  76. TestConvertHANDLEToFILEPtr(CreateMMapFileFromMem);
  77. TestConvertHANDLEToFILEPtr(CreateMMapFileFromFile);
  78. }
  79. }
  80. else
  81. {
  82. // TODO: 更改错误代码以符合您的需要
  83. _tprintf(_T("错误: GetModuleHandle 失败\n"));
  84. nRetCode = ;
  85. }
  86. return nRetCode;
  87.  
  88. }

输出结果如下:

二、如何通过FILE*访问内存块,尝试2:查找开源的类似fopen的实现函数

感觉我这种需求应该不算特殊,肯定有其他人和我有类似的需求。

既然标准c的库中没有接受byte[] 参数作为入参的重载版本,那么会不会有一些相关的开源实现呢?

用bing找到一篇和我类似需求的帖子,通过_iobuf关键字找到的:http://bytes.com/topic/c/answers/217166-typedef-struct-_iobuf-file

该楼主的大致需求也是想要用一个库,但是这个库的入参只接受FILE*作为,而他能够提供的内容都是基于内存的,不想使用磁盘文件作为中转。在这篇帖子找到了一个有人提到了fmemopen,funopen之类的类似fopen实现,他们可以接受byte[]为入参,然后返回一个FILE*。可惜的是,这些都只有linux版本,windows没有对应实现。我一直在想是不是要自己去包装一个,考虑到c库的复杂性,还是没法鼓起这个勇气。

三、如何通过FILE*访问内存块,尝试3:使用tmpfile_s()

上面之所以想要把内存转换为FILE*来使用,是因为觉得如果把解密之后的pyc文件临时放到内存中,有心人就可以直接把这个文件扒出来,然后反编译,那么有一种文件能够让人找不到路径,那实际上也能够达成目标。而tmpfile()可能就是这么一种潜在的方法。关于tmpfile()的各种实验,请参考:我的另一篇博文:

标准c的tmpfile()、tmpfile_s()生成的临时文件究竟放在哪里了?http://www.cnblogs.com/strinkbug/p/where_is_the_filepath_which_created_by_tmpfile_of_c.html  ),关于tmpfile研究的结果就是,window上,用tmpfile创建的文件,在磁盘上找不到对应的文件(虽然我也不太相信,但是确实没找到),所以使用tmpfile来创建FILE*可以部分的达到保密的目的。

四 结论

综上,没有找到可以在windows上直接把内粗块(比如byte[])的方法,linux上倒是有fmemopen之类的实现。考虑到tmpfile文件的隐蔽性,最终是选择使用tmpfile来实现我们的保密目的。

那么后续我就只要把python的pyc文件先解密,然后写入到tmpfile创建的临时文件FILE*中,然后再把这个FILE*往后传。

本系列还有:

Python解析器源码加密系列之(一):标准c的tmpfile()、tmpfile_s()生成的临时文件究竟放在哪里了?

Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试的更多相关文章

  1. Python解析器源码加密系列之(一):标准c的tmpfile()、tmpfile_s()生成的临时文件究竟放在哪里了?

    这两天由于修改python解释器的需求,需要用到tmpfile()来生成临时文件的FILE*,但是又担心这个临时文件是否存在于磁盘的某个地方,终究会被人找到,所以就简单做了以下几点实验,看看是否可以找 ...

  2. Alamofire源码解读系列(十二)之请求(Request)

    本篇是Alamofire中的请求抽象层的讲解 前言 在Alamofire中,围绕着Request,设计了很多额外的特性,这也恰恰表明,Request是所有请求的基础部分和发起点.这无疑给我们一个Req ...

  3. Netty 源码分析系列(二)Netty 架构设计

    前言 上一篇文章,我们对 Netty做了一个基本的概述,知道什么是Netty以及Netty的简单应用. Netty 源码分析系列(一)Netty 概述 本篇文章我们就来说说Netty的架构设计,解密高 ...

  4. Alamofire源码解读系列(十二)之时间轴(Timeline)

    本篇带来Alamofire中关于Timeline的一些思路 前言 Timeline翻译后的意思是时间轴,可以表示一个事件从开始到结束的时间节点.时间轴的概念能够应用在很多地方,比如说微博的主页就是一个 ...

  5. DRF之解析器源码解析

    解析器 RESTful一种API的命名风格,主要因为前后端分离开发出现前后端分离: 用户访问静态文件的服务器,数据全部由ajax请求给到 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己 ...

  6. Django 之 restframework 解析器源码分析

    解析器分类: 1. JSONPaser ----> 解析 JSON-serialized data (解析JSON序列化的数据) 2.FormParser ---->解析form 表单中 ...

  7. spring5源码分析系列(二)——spring核心容器体系结构

    首先我们来认识下IOC和DI: IOC(Inversion of Control)控制反转:控制反转,就是把原先代码里面需要实现的对象创建.依赖的代码,反转给容器来帮忙实现.所以需要创建一个容器,并且 ...

  8. Databend 源码阅读系列(二):Query server 启动,Session 管理及请求处理

    query 启动入口 Databend-query server 的启动入口在 databend/src/binaries/query/main.rs 下,在初始化配置之后,它会创建一个 Global ...

  9. jQuery-1.9.1源码分析系列(二)jQuery选择器

    1.选择器结构 jQuery的选择器根据源码可以分为几块 init: function( selector, context, rootjQuery ) { ... // HANDLE: $(&quo ...

随机推荐

  1. android多种布局的列表实现

    最近有一个列表效果,需要一个列表有多种布局,最终效果如下: 这个我也问了同事以及开发群里的朋友,居然都没得到最优的实现方式的回答,看来这种复杂列表的需求还是比较少的,我自己也走了一些弯路,把我几个实现 ...

  2. mysql ---复制表结构---创建新表

    1.复制表结构及数据到新表CREATE TABLE 新表SELECT * FROM 旧表这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete from newtable;来删 ...

  3. Mongo 的相关增删改查

    1,Mongod 下载安装,请看https://www.mongodb.com/download-center 2,插入语句: MongoDB后台管理 Shell 如果你需要进入MongoDB后台管理 ...

  4. sublime生产力提升利器

    sublime 操作快捷键功能-生产力提升利器 Go to anything  ctrl+p 支持快速模糊匹配 查找替换  ctrl+h 多行游标(当只需查找/替换/选中部分相同内容时)有以下方式来产 ...

  5. Python 元组知识点

    1.元组是一个有序的集合,2.元组和列表一样可以使用索引.切片来取值.3.创建元组后不能在原地进行修改替换等操作.4.元组支持嵌套,可以包含列表.字典和不同元组.5.元组支持一般序列的操作,例如:+. ...

  6. 【对比分析八】null和undefined的区别

    (1).  null是一个表示"无"的对象,转为数值时为0  undefined是一个表示"无"的原始值,转为数值时为NaN (2).  当声明的变量还未被初始 ...

  7. Head First HTML5 Programming 读书笔记

    1:HTML5引入了简单化的标记,新的语义和媒体元素,另外要依赖于一组支持web应用的js库. 2:关于js 对象是属性的结合 window对象是全局变量. document对象是window的一个属 ...

  8. ssm中使用hibernate-validator验证BO

    目前比较流行的验证做法:前端jquery-form-validate + 后端hibernate-validate 在pom中添加相关jar: <!-- use hibernate-valida ...

  9. FlashInspector 【Firefox浏览器插件,flash分析工具】

    Inspect flash(swf)'s DisplayObject with mouse. Overview the swf's DisplayObject list. Set the inspec ...

  10. Linux搭建PHP+MySQL+Apache环境

    环境: CentOS 6.4 MySQL详细安装可参考:http://www.cnblogs.com/yangxia-test/archive/2012/11/12/2766237.html Apac ...