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

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

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

struct _iobuf {
char *_ptr; //文件输入的下一个位置
int _cnt; //当前缓冲区的相对位置
char *_base; //指基础位置(应该是文件的其始位置)
int _flag; //文件标志
int _file; //文件的有效性验证
int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
int _bufsiz; //文件的大小
char *_tmpfname;//临时文件名
};
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是无效的.

下面是实验代码:

#include "stdafx.h"
#include "TestMemFile.h"
#include <io.h>
#include <fcntl.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif // 唯一的应用程序对象 CWinApp theApp;
using namespace std; HANDLE CreateMMapFileFromMem()
{
TCHAR* MF_NAME = _T("MF_FILE_NAME_TEST");
int MF_SIZE = *;
std::cout<<"create a mem map file from mem"<<std::endl;
return CreateFileMapping(INVALID_HANDLE_VALUE,
NULL, PAGE_READWRITE, ,
MF_SIZE, MF_NAME);
} HANDLE CreateMMapFileFromFile()
{
std::cout<<"create a normal file"<<std::endl;
//这里我事先已经在D盘创建好文件,并且内容是字符 aaa
HANDLE hFile = CreateFile(L"D:\\TestMemMapFile.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL, NULL);
return hFile;
} /*一个用于创建内存映射文件的函数指针*/ typedef HANDLE (*CREATE_FILE_HANDLE)(void); void TestConvertHANDLEToFILEPtr(CREATE_FILE_HANDLE lpCreateFile)
{
HANDLE hFile = lpCreateFile();
if(hFile == nullptr)
{
std::cout<<"create file failed."<<std::endl;
return;
}
int hfd = _open_osfhandle((intptr_t)hFile, _O_RDONLY); if(hfd == -)
{
std::cout<<"convert File HANDLE to FILE* failed."<<std::endl;
CloseHandle(hFile);
return;
}
std::cout<<"convert File HANDLE to FILE* success. "<<std::endl;
FILE* fd = _fdopen(hfd,"r");
char c = getc(fd);
std::cout<<"use getc(fd) to read a char from converted fd success, the char value is :" << c << std::endl;
fclose((FILE*)fd);
} int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
int nRetCode = ;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// 初始化 MFC 并在失败时显示错误
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), ))
{
// TODO: 更改错误代码以符合您的需要
_tprintf(_T("错误: MFC 初始化失败\n"));
nRetCode = ;
}
else
{
// TODO: 在此处为应用程序的行为编写代码。
TestConvertHANDLEToFILEPtr(CreateMMapFileFromMem);
TestConvertHANDLEToFILEPtr(CreateMMapFileFromFile);
}
}
else
{
// TODO: 更改错误代码以符合您的需要
_tprintf(_T("错误: GetModuleHandle 失败\n"));
nRetCode = ;
}
return nRetCode; }

输出结果如下:

二、如何通过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 启动过程简析

    首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...

  2. Visual Studio发布Web项目报错:Unable to add 'xxx' to the Web site. Unable to add file 'xxx'. The specified file could not be encrypted.

    背景 Visual Studio下的Web项目 现象 发布时遇到Unable to add 'xxx' to the Web site.  Unable to add file 'xxx'. The ...

  3. [Derby]数据库操作说明

    1. 创建新数据库 connect 'jdbc:derby:mydb;create=true'; ij> connect 'jdbc:derby:mydb;create=true'; ij> ...

  4. 测试管理_下属谈话[持续更新ing]

    作为测试部门的管理者,在工作绩效评定.工作安排.工作问题提出等时候,都需要与下属进行面对面谈话,怎么进行有效的谈话,这是一个值得思考和锻炼的问题. 谈话的内容: 谈近阶段工作的回顾 谈工作中的困难(是 ...

  5. Effective Java 62 Document all exceptions thrown by each method

    Principle Always declare checked exceptions individually, and document precisely the conditions unde ...

  6. postfix删除队列中的邮件

    Postfix中有一套Mail Queue Management机制,所有队列中的邮件都可以全自动的处理,但在发送大量邮件的时候,有必要对这个队列进行手工的维护处理,比如说,删除队列中的邮件. 以下是 ...

  7. 一个自定义 HBase Filter -“通过RowKeys来高性能获取数据”

    摘要: 大家在使用HBase和Solr搭建系统中经常遇到的一个问题就是:“我通过SOLR得到了RowKeys后,该怎样去HBase上取数据”.使用现有的Filter性能差劲,网上也没有现成的自定义Fi ...

  8. 迅为4412开发板支持AVIN视频输入/AV监控摄像头输入模块

    AVIN模块(iTOP-4412开发板专用) 产品介绍:视频输入/AV监控摄像头输入模块: 该模块及配套的软件为开发视频采集.监控.车载后视等产品提供了很好的参考. iTOP-4412 开发平台 开发 ...

  9. Hive2 jdbc test

    package andes; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOExce ...

  10. 1644 免费馅饼 题解(c++)(S.B.S.)

    1644 免费馅饼(巴蜀oj上的编号) 题面:          SERKOI最新推出了一种叫做“免费馅饼”的游戏.         游戏在一个舞台上进行.舞台的宽度为W格,天幕的高度为H格,游戏者占 ...