先放一个例子:
这个例子是从本地读出一个文件存入数组,然后让文件的每一个二进制位(一个字节)与0x12相与,之后的数据存入另一个二进制文件:
利用fread、fwrite函数
#include <stdio.h>
#include <stdlib.h>
long _filesize(FILE *stream)
{
long curpos, length;
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
fseek(stream, curpos, SEEK_SET);
return length;
}
int main()
{
FILE *fp;
FILE *wp;
if ((fp = fopen("flag", "rb")) == NULL)
return 0;
printf("You can get flag by reading the code.\n");
long buffsize = _filesize(fp);
char *buff = (char *)malloc(buffsize * sizeof(char));
fread(buff, buffsize, 1, fp);
fclose(fp);
char m[10000];
for (int i = 0; i < buffsize; i++) {
m[i] = buff[i];
}
/*for (int i = 0; i < buffsize; i++) { //显示前10个字符
printf("%x ", m[i]);
}*/
/*
for (i = 0; i < buffsize; i++) { //显示前10个字符
printf("%x ", (unsigned char)buff[i]);
}*/
for (int i = 0; i < buffsize; i++) { //显示前10个字符
m[i] ^= 0x12;
m[i] -= 10;
}
wp = fopen("flagout", "wb");
fwrite(m, 1, buffsize, wp);
fclose(wp);
free(buff);
system("pause");
return 0;
}
C语言读取二进制文件:
FILE *fp;
if ((fp = fopen("flag", "rb")) == NULL)
return 0;
long buffsize = _filesize(fp);
char *buff = (char *)malloc(buffsize * sizeof(char));
fread(buff, buffsize, 1, fp);
fclose(fp);
free(buff);
写入文件:
FILE *wp;
wp = fopen("flagout", "wb");
fwrite(m, 1, buffsize, wp);
fclose(wp);
fseek函数
函数名:fseek函数
头文件:#include<stdio.h>
功能:把与fp有关的文件位置指针放到一个指定位置。
格式: int fseek(FILE *stream, long offset, int fromwhere);
范例一:fseek(fp, 0L, SEEK_END);
解释:文件指针定位到文件末尾,偏移0个字节
范例二: fseek(fp,50L,0);或fseek(fp,50L,SEEK_SET);
解释:其作用是将位置指针移到离文件头50个字节处。
起始点 | 对应的数字 | 代表的文件位置 | |
---|---|---|---|
SEEK_SET | 0 | 文件开头 | |
SEEK_CUR | 1 | 文件当前位置 | |
SEEK_END | 2 | 文件末尾 |
说明:
offset:偏移量
fromwhere:起始位置
其中,“位移量”是long型数据,它表示位置指针相对于“起始点”移动的字节数。
如果位移量是一个正数,表示从“起始点”开始往文件尾方向移动;
如果位移量是一个负数,则表示从“起始点”开始往文件头方向移动。
“起始点”不能任意设定,它只能是在stdio.h中定义的三个符号常量之一:
注意:<br
fseek函数的文件指针,应该为已经打开的文件。如果没有打开的文件,那么将会出现错误。
以上内容来自网络上资料,整理结果。
下面请看例题:
例题代码:
#include <stdio.h>
#include <stdlib.h>//fseek函数调用
int main()
{
// 开始文件中的内容为aaaaaaaaa
FILE * fp = fopen("a.txt", "r+");
if (fp == NULL) {
printf("file error\n");
exit(1);
}
fseek(fp, 2, SEEK_SET);//光标移到文件开始起第二个字节处。
fwrite("yun", 1, 3, fp); //文件内写入内容yun
fclose(fp);
return 0;
}
Python读写二进制文件
struct模块
struct模块的内容不多,也不是太难,下面对其中最常用的方法进行介绍:
1、 struct.pack
struct.pack用于将Python的值根据格式符,转换为字符串(因为Python中没有字节(Byte)类型,可以把这里的字符串理解为字节流,或字节数组)。其函数原型为:struct.pack(fmt, v1, v2, …),参数fmt是格式字符串,关于格式字符串的相关信息在下面有所介绍。v1, v2, …表示要转换的python值。
2、 struct.unpack
struct.unpack做的工作刚好与struct.pack相反,用于将字节流转换成python数据类型。它的函数原型为:struct.unpack(fmt, string),该函数返回一个元组。
下面的例子将两个整数转换为字符串(字节流):
import struct
a = 20
b = 400
s = struct.pack('ii', a, b)
print(s, type(s))
#输出:b'\x14\x00\x00\x00\x90\x01\x00\x00' <class 'bytes'>
print('length: ', len(s))
#输出:length: 8
s2 = struct.unpack('ii', s)
print(s2)
#输出:(20, 400)
s2 = struct.unpack('ii', s)
报错:unpack requires a buffer of 4 bytes
==>解压需要一个4字节的缓冲区,也就是说’ii’表示8个字节的缓冲
格式符”i”表示转换为int,’ii’表示有两个int变量。
进行转换后的结果长度为8个字节(int类型占用4个字节,两个int为8个字节)
可以使用python的内置函数repr来获取可识别的字符串,其中十六进制的0x00000014, 0x00001009分别表示20和400。
3、 struct.calcsize
struct.calcsize用于计算格式字符串所对应的结果的长度,如:struct.calcsize(‘ii’),返回8。因为两个int类型所占用的长度是8个字节。
1 import struct
2 print "len: ", struct.calcsize('i') # len: 4
3 print "len: ", struct.calcsize('ii') # len: 8
4 print "len: ", struct.calcsize('f') # len: 4
5 print "len: ", struct.calcsize('ff') # len: 8
6 print "len: ", struct.calcsize('s') # len: 1
7 print "len: ", struct.calcsize('ss') # len: 2
8 print "len: ", struct.calcsize('d') # len: 8
9 print "len: ", struct.calcsize('dd') # len: 16
4、 struct.pack_into、 struct.unpack_from
这两个函数在Python手册中有所介绍,但没有给出如何使用的例子。其实它们在实际应用中用的并不多。Google了很久,才找到一个例子,贴出来共享一下:
1 #!/usr/bin/env python
2 #encoding: utf8
3
4 import sys
5 reload(sys)
6 sys.setdefaultencoding("utf-8")
7
8 import struct
9 from ctypes import create_string_buffer
10
11 buf = create_string_buffer(12)
12 print repr(buf.raw) # '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
13
14 struct.pack_into("iii", buf, 0, 1, 2, -1)
15 print repr(buf.raw) # '\x01\x00\x00\x00\x02\x00\x00\x00\xff\xff\xff\xff'
16
17 print struct.unpack_from("iii", buf, 0) # (1, 2, -1)
struct 类型表
Format | C Type | Python type | Standard size | Notes | |
---|---|---|---|---|---|
x | pad byte | no value | |||
c | char | string of length 1 | 1 | ||
b | signed char | integer | 1 | (3) | |
B | unsigned char | integer | 1 | (3) | |
? | _Bool | bool | 1 | (1) | |
h | short | integer | 2 | (3) | |
H | unsigned short | integer | 2 | (3) | |
i | int | integer | 4 | (3) | |
I | unsigned int | integer | 4 | (3) | |
l | long | integer | 4 | (3) | |
L | unsigned long | integer | 4 | (3) | |
q | long long | integer | 8 | (2), (3) | |
Q | unsigned long long | integer | 8 | (2), (3) | |
f | float | float | 4 | (4) | |
d | double | float | 8 | (4) | |
s | char[] | string | 1 | ||
p | char[] | string | |||
P | void * | integer | (5), (3) |
一个python读取二进制文件,然后经过一系列变换重新写入文件:
import struct
with open("flagout","rb") as f:
readbuf=f.read(3914)#3914=len(f.read())
data=struct.unpack("3914B",readbuf)
#print(data)
listbuf=[]
for i in data:
i+=10
i^=0x12
listbuf.append(i&0xff)#有溢出
#print(listbuf)
with open('out', 'wb')as fp:
for x in listbuf:
a = struct.pack('B', x)
fp.write(a)