是否可以拦截matlab save()字节流

时间:2011-01-26 16:26:27

标签: serialization matlab save

在matlab中,可以使用matlab save()调用将matlab对象甚至整个工作区写入文件。我想拦截字节流并在它转到文件之前对其进行后处理,这可能吗?或者,是否可以指定写入字节流的filedescriptor而不是通常作为参数进入save()调用的文件名。

请注意,我不是在寻找另一种在matlab中编写文件的方法,我知道我可以fopen()一个文件并编写我想要的任何内容,但重点是我想(重新)使用该对象保存调用内部的序列化,而不是再发明一次。

当然会出现load()调用的模拟问题,但在这种情况下,在进入反序列化过程之前拦截字节流,但我想如果save()可以解决load()的问题问题会自然而然地发生。

一些澄清:

  1. 我不是在寻找一种新的方法来序列化matlab数据,它已经存在,而且练习的重点是在save()调用中使用现有的序列化,以便1)我不需要在较新版本的matlab中开始更新新类型对象的序列化代码,或天堂禁止人们开始使用自定义OOP对象,2)我仍然可以轻松地使用现有代码读取mat文件,例如scipy的支持用于mat文件。

  2. 在进行后处理之前,流不得出现在文件或任何内容中,这个想法是加密安全性,将流明文写入文件完全破坏了这一目的。

  3. 并发症:

    • 似乎matlab中save函数中使用的功能不仅仅是常规顺序写入。检查库的目标代码,似乎使用matPutVariable(以前称为matPutArray)实现了save函数,该函数将类型为mxArray*的给定变量写入MATFile*类型的文件中。 1}}以matOpen打开。这里的问题是matPutVariable

      的描述中的以下文字
        

      如果MAT文件中不存在mxArray,则该函数将其追加到末尾。如果文件中存在具有相同名称的mxArray,则该函数会通过重写文件将现有的mxArray替换为新的mxArray

      这意味着matPutVariable函数必须通过该文件进行搜索,显然在使用管道时将无法进行搜索,因此在使用此现有序列化时,无法使用管道来实现对字节流的处理功能。

10 个答案:

答案 0 :(得分:5)

如何使用虚拟文件系统?在Windows上有一个名为BoxedAPP SDK的商业库,它允许您创建仅对创建过程可见的虚拟文件(也可能是子项)。你可能需要制作一个MEX来连接库。首先,您将创建虚拟文件,然后您可以在matlab中使用具有相同文件名的save命令。然后你可以使用matlab中的普通fopen / fread函数读取序列化的.mat字节流,并随心所欲地执行它。这至少会阻止在硬盘上创建文件。我不确定在文件实际创建到内存时,文件或部分内容是否可以到达交换文件。

在libmx中似乎还有未记录的函数mxSerialize和mxDeserialize,例如。通过loadlibrary / calllib函数直接从matlab或包装器mex。一些谷歌搜索显示这些功能的签名应该是

mxArray* mxSerialize(const mxArray*);
mxArray* mxDeserialize(const void*, size_t);

并且一些测试显示mxSerialize()获取matlab变量作为参数并返回序列化字节作为uint8数组。 mxDeserialize()将此uint8数组(第一个参数)转换回matlab对象作为返回值。 mxDeserialize的第二个参数似乎是第一个参数中的元素数。但是,使用这些未记录的函数不会保证将来可用,因为TMW可能会更改API。

答案 1 :(得分:2)

编辑:(基于评论)嗯,我想我的旧回答并没有多大帮助。我不知道你会如何拦截字节流,但我想你有一个选项(这无疑是一个小问题)只是 SAVE函数创建文件,然后立即逐字节地从文件中读取数据,处理它,并将其写回文件。类似的东西:

save('workspace.mat');
fid = fopen('workspace.mat','r');
byteData = fread(fid,inf,'*uint8');
fclose(fid);
%# ... Process byteData here ...
fid = fopen('workspace.mat','w');
fwrite(fid,byteData,'uint8');
fclose(fid);

旧回答:

对于用户定义的类对象,我相信您正在寻找的内容体现在重载的SAVEOBJLOADOBJ方法中,这些方法在将对象保存到或从中加载之前在对象上调用一份文件。当saving or loading objects与.MAT文件相关时,您可以将这些方法用于modify the save/load process,以便可以以不同方式对对象进行格式化。但是,我认为您不能对内置数据类型执行此操作,仅适用于用户定义的对象。

答案 2 :(得分:2)

对于HG对象,您可以通过此处说明的内部(可修改)* .m文件拦截保存处理: http://undocumentedmatlab.com/blog/handle2struct-struct2handle-and-matlab-8/

答案 3 :(得分:2)

最好的办法是将mat文件写入tmpfs / ramdisk,然后在将其保存到磁盘之前对其进行加密。您牺牲了可移植性并依赖操作系统来提供安全的虚拟内存,但如果您甚至不能信任本地磁盘,那么您可能无法获得满意的安全性。

顺便说一句,为什么你根本不能完全信任本地磁盘,即使你不能将你的临时文件放在一个目录中,权限设置为只允许拥有matlab进程的用户访问(和根)?您是否尝试实施DRM系统?

答案 4 :(得分:2)

你不能加密变量的内容吗?

使用whos,您可以按字母顺序获取所有变量的列表。对于每一个,您使用加密算法生成相同大小的掩码,并将掩码替换为“true”值。要完成,请使用save保存加密变量。变量的名称和大小是可见的,但这可能并不重要(如果需要,您也可以使用加密名称)。

以相同的方式加载。

答案 5 :(得分:2)

使用getByteStreamFromArraygetArrayFromByteStream进行序列化/反序列化。您可以在将结果字节写入文件

之前修改它们
% A cell array of several data types
>> byteStream = getByteStreamFromArray({pi, 'abc', struct('a',5)});  % 1x312 uint8 array
>> getArrayFromByteStream(byteStream)
ans = 
    [3.14159265358979]    'abc'    [1x1 struct]

正如http://undocumentedmatlab.com/blog/serializing-deserializing-matlab-data

所述

答案 6 :(得分:1)

也许您可以执行以下操作:

%# serialize objects into a byte array using Java
bout = java.io.ByteArrayOutputStream();
out = java.io.ObjectOutputStream(bout);
out.writeObject( rand(3) )                %# MATLAB matrix
out.writeObject( num2cell(rand(3)) )      %# MATLAB cell array
out.flush()
out.close()
bout.close()
b = bout.toByteArray();                   %# vector of type int8

%# perform processing on `b` ...

%# write byte[] stream to file
save file.mat b

然后在相反的方向上,您只需加载已保存的MAT文件,反转您执行的任何处理,并反序列化字节流以回收原始对象。

%# load MAT-file
load file.mat b
b = typecast(b,'int8');                   %# cast as int8 just to be sure

%# undo any processing on `b`...

%# deserialize
in = java.io.ObjectInputStream( java.io.ByteArrayInputStream(b) );
X1 = double( in.readObject() )            %# recover matrix
X2 = cell( in.readObject() )              %# recover cell array
in.close()

请注意,您必须自己维护变量元信息,例如它们的数量和类型(也许您可以以某种方式将其保存在同一个MAT文件中),并使用自定义包装函数来处理所有编组,但你明白了......


我还发现了一些有关FEX的提交,有助于序列化/反序列化MATLAB类型:

答案 7 :(得分:1)

我也对这个问题感兴趣。我发现了一些东西,但没有任何作用:

  • matlab save stdio 你发现这个隐藏的功能,但它不起作用
  • engGetArray / engPutArray “此例程允许您将变量复制出工作区。”

查看MAT文件规范,也许我们可以使用Mex文件重现matlab序列化:

更新

我发现了一些非常有趣的东西:在Matlab控制台中运行这个命令

edit([matlabroot '/extern/examples/eng_mat/matcreat.c']);

或者

edit([matlabroot '/extern/examples/eng_mat/matcreat.cpp']);

这是文档,如何编译它:http://www.mathworks.com/help/techdoc/matlab_external/f14500.html

在我看来,在pmat = matOpen(file, "w");命令中使用STDOUT应该是可行的。

答案 8 :(得分:0)

经过几个月的沉思,我会说,不,这是不可能的。至少,不是没有硬核非便携式二进制/ ELF黑客攻击。

答案 9 :(得分:-1)

步骤1:mkfifo /tmp/fifo - 这会创建一个FIFO,一个代表管道的文件名。写入管道的任何内容都会保留在那里,直到进程将其从管道中读回。数据永远不会到达磁盘。

步骤2:在一个终端中运行:openssl enc -aes-256-cbc -a -e -in fifo -out safe - 运行OpenSSL程序,使用AES,256位密钥,CBC模式加密(openssl支持更多密码类型和参数,选择一个适合你,这是一个安全的默认); -a Base64对输出进行编码(这对于测试很有用,但是当你真正使用它时你可能会把它关闭,Base64会导致4/3的大小增加); -e以加密模式运行,-in fifo指定输入文件名为fifo(可能使用完整路径); -out safe指定输出文件名为safe(同样,可能使用完整路径)。 OpenSSL将一直睡眠,直到数据到达管道。

当某些数据到达管道时,OpenSSL会提示您输入密码。

测试出来:在另一个终端中运行“echo foo> / tmp / fifo”。查看第一个终端中的密码提示,给它一个密码并确认密码,然后查看文件'safe'的内容:

$ openssl enc -aes-256-cbc -a -e -in fifo -out safe
# (in another terminal, "echo foo > fifo")
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
$ cat safe
U2FsdGVkX18aWBw0Uz8N3SfrRg4PigL609F+HQPuc6o=

测试另一个方向:

$ openssl enc -aes-256-cbc -a -d -in safe
enter aes-256-cbc decryption password:
foo

现在,重新运行步骤2中的OpenSSL命令:openssl enc -aes-256-cbc -a -e -in fifo -out safe,运行Matlab,并将/tmp/fifo提供给SAVE()命令。

>名为/tmp/fifo的常规文件。所以请先测试一些不重要的数据。但我希望Matlab是用Unix工具编写的,只需写入你给它的命名管道。