以下程序是一个信息编码的程序,阅读其encode部分,并补全其decode部分
最后运行程序,会打印出的一句话。这句话就是我们要求的答案。 (本段代码遵循c99标准,gcc编译请加-std=c99)
注意!这句话是用GBK编码的!
题目:
#include <stdio.h>
#include <stdlib.h>
//#include <stdint.h>
#include <assert.h>
#include <string.h>
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
int encode(const void* raw_in, void* raw_out, uint32_t password, size_t len)
{
const uint8_t* in = (const uint8_t*)raw_in;
uint8_t* out = (uint8_t*)raw_out;
uint32_t seed = password ^ 0x12cfd592u;
for (size_t i = 0 ; i < len; ++i) {
uint8_t a = ( in[i] ^ seed ) >> 2;
uint8_t b = ( ( ((uint32_t)in[i]) << 12 ) ^ seed ) >> (12-6);
a &= 63;
b &= 192;
a = 63 & ( a ^ (b << 3));
out[i] = a | b;
seed = (seed * 3687989 ^ seed ^ out[i]);
}
return 0;
}
int decode(const void* raw_in, void* raw_out, uint32_t password, size_t len)
{
const uint8_t* in = (const uint8_t*)raw_in;
uint8_t* out = (uint8_t*)raw_out;
uint32_t seed = password ^ 0x12cfd592u;
for (size_t i = 0 ; i < len; ++i) {
// 请在此处补全代码
uint8_t a = in[i] & 63;
uint8_t b = in[i] & 192;
uint8_t c = ((a<<2) ^ seed ) &252;
uint8_t d = (((((uint32_t) b) << 6) ^ seed) >> 12) & 3;
out[i] = c | d;
seed = ( seed * 3687989 ^ seed ^ in[i]);
}
return 0;
}
int main()
{
const uint8_t buf1[] = {0x5f, 0x5f, 0x1c, 0x19, 0x87, 0x01, 0x9b, 0xfc, 0x50, 0x85, 0x43, 0xa9, 0x82, 0xed, 0xde, 0x9e, 0x20, 0xa3, 0x70, 0xc9, 0x10, 0x67, 0xd9, 0x15, 0xd8, 0x97, 0x4b, 0xa2, 0xd1, 0x6d, 0x7f, 0xdb, 0x57,
0xca, 0xa1, 0x7e, 0x8f, 0x54, 0xd2, 0x4d, 0x4b, 0x4b, 0x9e, 0x82, 0x74, 0xec, 0x4f, 0x0f, 0x36, 0x66, 0xbf, 0x4d, };
uint8_t buf2[100] = {};
const uint32_t password = 0xa97e3826u;
const size_t len = sizeof(buf1);
decode(buf1, buf2, password, len);
printf("%s\n", buf2);
system("PAUSE");
return 0;
}
输出结果为:
搜狗拼音输入法开创了基于搜索引擎全新的输入模式!!!
解题思路:
推反的过程。
uint8_t a = ( in[i] ^ seed ) >> 2;
//in[i]为uint_t类型的元素,有8个bit位,与32位种子做异或操作,之后向右移两位(未知)得到的结果为??xxxxxx,保存在a中,原来in[i]与seed做异或操作后的低6位结果保存在a中
uint8_t b = ( ( ((uint32_t)in[i]) << 12 ) ^ seed ) >> (12-6);
//同理先将in[i]转化为32位数,向左移动12位,与种子做异或操作,再将其右移6位后(未知),将其赋值给uint8_t变量b中得到xx??????。原来in[i]与seed做异或操作后的高2位结果保存在b中
a &= 63;
//做与操作,63的二进制形式为00111111;a & 63将a的高两位置零,a变为:00xxxxxx
b &= 192;
//与操作,192的二进制形式为11000000;b & 192 将b的低6位置零,b变为:xx000000
a = 63 & ( a ^ (b << 3));
//仔细算来,该操作并未改变a的值,属于误导的操作,分析如下,b<<3得到0000000 a为00xxxxxx a^(b<<3)结果为 00xxxxxx & 00111111= 00xxxxxx;
out[i] = a | b;
//00xxxxxx | xx000000,将加密后的前2位和后两位组合起来
seed = (seed * 3687989 ^ seed ^ out[i]);
//每次依据加密后的值改变种子的行为
解码部分:
uint8_t a = in[i] & 63;
//得到加密数据的后6位 保存为a
uint8_t b = in[i] & 192;
//得到加密数据的前2位 保存为b
uint8_t c = ((a<<2) ^ seed ) &252;
//做逆操作根据a=b ^ c,得 b=a ^ c,对加密部分uint8_t a = ( in[i] ^ seed ) >> 2; 的逆转,由于>>2导致该部分数据形式为xxxxxx??将其未置部分数据清零即 &252 (11111100)
uint8_t d = (((((uint32_t) b) << 6) ^ seed) >> 12) & 3;
//做逆操作根据a=b ^ c,得 b=a ^ c,对加密部分 uint8_t b = ( ( ((uint32_t)in[i]) << 12 ) ^ seed ) >> (12-6); ,由于<<12 并且 >>6得到??????xx将其未置部分数据清零
&3(00000011)
out[i] = c | d;
//将两部分数据组合在一起
seed = ( seed * 3687989 ^ seed ^ in[i]);
//种子部分的双方保持一致,原来的out[i]保存的是加密的数据,现在in[i]保存的是加密的数据,因此应该置为上述表达
(encode decode sougou)