[Hgame CTF]easyenc

考点一览

小端序

十六进制的的拆分

我们在ida里可以看到一个由许多个数字组成的十进制整数,这时我们按‘H’,则能将其转化为十六进制的整数。因为这个十六进制的整数按字节储存在内存条中,且一个字节就是8个位。我们知道,在内存条中,任何数字或字母都是按二进制的形式储存。由于我们十六进制中最大的‘F’的二进制也不过‘1111’,因此在同一字节中,我们会存放两个字符。

小端序的排法

综上,我们知道十六进制的字符要以二进制形式排列在内存条中,而小端序则是其中一种排列方式。我们知道,数据的前端是高位,在内存条中则后端是高位。而小端序排法:就是将数据高位的的字符存入内存条的高位
例如:0x12345678(数据),则0x12是高位,会被存到内存条中靠后的位置。在内存条中的则为:0x78 0x56 0x34 0x12.输出为0x78 0x56 0x34
0x21(本人学艺不精,试验后只知道拆分后的输出结果)

代码算法理解的常见问题

我们在将十六进制整数按内存条排列进行拆分的时(如上例),往往利用算法比较方便,例如:

int enc[]={0x4,0xff,0xfd,0x9,0x1,0xf3,0xB0};
char enc[256]={0};
long long v8[20]={0};
int main ()
{
	v8[0] = 0x9FDFF04;
	v8[1] = 0xB0F301;
	v8[2] = 0xADF00500;
	v8[3] = 0x5170607;
	v8[4] = 0x17FD17EB;
	v8[5] = 0x1EE01EA;
	v8[6] = 0xFA05B1EA;
	v8[7] = 0xAC170108;
	v8[8] = 0xFDEA01EC;
	v8[9] = 0x60705F0;
	enc[40]=0xF9;	
	for(int i = 0 ; i <10 ; i ++ )
	{
		long long *p = (long long *)(enc+i*4);
		*p += v8[i];
	}
	
	
	for(int i = 0 ; i < 41 ; i++ )
	{
		printf("%c",(enc[i]+86)^0x32);
	}
}

ps:本段代码来自五边形战士shangwendada

int main ()
{
	int  v8[10];
	char enc[41]={0};
	enc[0] = 0x04;
	enc[1] = 0xFF;
	enc[2] = 0xFD;
	enc[3] = 0x09;
	enc[4] = 0x01;
	enc[5] = 0xF3;
	enc[6] = 0xB0;
	enc[7] = 0x00;
	enc[8] = 0x00;
	enc[9] = 0x05;
	enc[10] = 0xF0;
	enc[11] = 0xAD;
	enc[12] = 0x07;
	enc[13] = 0x06;
	enc[14] = 0x17;
	enc[15] = 0x05;
	enc[16] = 0xEB;
	enc[17] = 0x17;
	enc[18] = 0xFD;
	enc[19] = 0x17;
	enc[20] = 0xEA;
	enc[21] = 0x01;
	enc[22] = 0xEE;
	enc[23] = 0x01;
	enc[24] = 0xEA;
	enc[25] = 0xB1;
	enc[26] = 0x05;
	enc[27] = 0xFA;
	enc[28] = 0x08;
	enc[29] = 0x01;
	enc[30] = 0x17;
	enc[31] = 0xAC;
	enc[32] = 0xEC;
	enc[33] = 0x01;
	enc[34] = 0xEA;
	enc[35] = 0xFD;
	enc[36] = 0xF0;
	enc[37] = 0x05;
	enc[38] = 0x07;
	enc[39] = 0x06;
	enc[40] = 0xF9;
	/*for(int i=0;i<10;i++)
	{
		int *p;
		p=(int *)(enc+i*4);//p为enc的地址,一个小端序包含了4个十六进制的元素,所以此处要*4。
		*p+=v8[i];//p地址上的初始值为0,+v8[i]则改变p指针所指向位置的值,而这个位置初始化的时候是0
	}*/
	//作用是将V8数组中0x12345678,改为0x78 0x56 0x34 0x12存入enc数组中。
	for(int i=0;i<41;i++)
	{
	printf("%c",(enc[i]+86)^0x32);
	}
}

ps:这是我为了方便理解,对学长代码改编,结果是一样的。0x1补成0x01,是为了美观,并无影响。根据本题,没有占据四个字节的十六进制整数,要在内存条的高位补上0x00.
最后,结果之所以是逆序,是计算机自动的,而非通过算法实现的。

十六进制以小端序的方式排列

方法一

for(int i=0;i<10;i++)
	{
		int *p;
		p=(int *)(enc+i*4);//p为enc的地址,一个小端序包含了4个十六进制的元素,所以此处要*4。
		*p+=v8[i];//p地址上的初始值为0,+v8[i]则改变p指针所指向位置的值,而这个位置初始化的时候是0
	}
//作用是将V8数组中0x12345678,改为0x78 0x56 0x34 0x12存入enc数组中。

方法二

for(int i = 0 ; i < 8 ; i++ ) //有i个十六进制元素的数组
	{
		unsigned int tmp = Buf2[i];
		for(int j = 0 ; j< 4 ; j++ ) //两个字符为一组,jmax=组成元素的字符个数/2-1
		{
			printf("0x%x ",tmp%0x100);//取最末端的两个字符
			tmp/=0x100;//让tmp=剩下的数
		}
	}

简单解题

解决了小端序的问题,接下来就是算法问题
file
v3这个表示初始值为0,v4的初始值为-1。因为一开始不知道,所以在这里卡了很久。后面就直接通过明显的±和^完成了脚本,得到了flag。
hgame{4ddit1on_is_a_rever5ible_0peration}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值