个人网站建设设计/百度搜索高级搜索
目录
Base
IKUN检查器
dnSpy
junk code
Cheat Engine工具使用:
奇怪的ELF
mov混淆问题:
Xor
Base
打开附件,可以看到主函数
先是给出一个物理题,要求输入答案,这个无关紧要,接着要求输入一串字符,经过encode_1和encode_2的加密过程后,要求等于enflag。直接进入encode_1和encode_2查看
encode_1:
char __cdecl encode_1(char *flag, int num)
{size_t v2; // raxint i; // [rsp+2Ch] [rbp-54h]for ( i = 0; ; ++i ){v2 = strlen(flag);if ( i >= v2 )break;if ( flag[i] <= 64 || flag[i] > 90 ){if ( flag[i] > 96 && flag[i] <= 122 )flag[i] = (flag[i] - 97 + num) % 26 + 97;}else{flag[i] = (flag[i] - 65 + num) % 26 + 65;}}return v2;
}
很明显的凯撒加密,偏移量是num,传进去的参数可以知道num的值为3.
再进入encode_2查看
char __cdecl encode_2(char *str, int len, char *str1)
{int v3; // eaxint v4; // eaxint v5; // eaxint v6; // r8dint v7; // eaxint v8; // r8dint v9; // eaxint v10; // eaxint v11; // eaxint v12; // r8dint v13; // eaxint v14; // eaxint v15; // eaxint v16; // eaxchar base64[65]; // [rsp+20h] [rbp-60h] BYREFchar *flag; // [rsp+68h] [rbp-18h]int encodeStrLen; // [rsp+74h] [rbp-Ch]int k; // [rsp+78h] [rbp-8h]int i; // [rsp+7Ch] [rbp-4h]strcpy(base64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");encodeStrLen = 4 * (len / 3) + 1;k = 0;if ( len % 3 )v3 = 4;elsev3 = 0;encodeStrLen += v3;flag = malloc(encodeStrLen);for ( i = 0; i < len; ++i ){if ( len - i <= 2 ){v10 = k++;if ( len - i == 2 ){flag[v10] = base64[str[i] >> 2];v11 = k++;v12 = 16 * (str[i++] & 3);flag[v11] = base64[v12 | (str[i] >> 4)];v13 = k++;flag[v13] = base64[4 * (str[i] & 0xF)];}else{flag[v10] = base64[str[i] >> 2];v15 = k++;flag[v15] = base64[16 * (str[i] & 3)];v16 = k++;flag[v16] = 61;}v14 = k++;flag[v14] = 61;}else{v4 = k++;flag[v4] = base64[str[i] >> 2];v5 = k++;v6 = 16 * (str[i++] & 3);flag[v5] = base64[v6 | (str[i] >> 4)];v7 = k++;v8 = 4 * (str[i++] & 0xF);flag[v7] = base64[v8 | (str[i] >> 6)];v9 = k++;flag[v9] = base64[str[i] & 0x3F];}}flag[k] = 0;return strcpy(str1, flag);
}
一个base64加密
最后将加密后的数据与enflag进行比较,解密过程就是先将enflag进行base64解码,然后再将得到的值进行凯撒解密,偏移量为3最后得到flag。
IKUN检查器
打开附件,可以发现是c#编写的程序,c#程序需要使用dnSpy打开
dnSpy
可以直接从官网上下载
打开可以看到主函数
// WindowsFormsApp1.From1
// Token: 0x06000006 RID: 6 RVA: 0x00002074 File Offset: 0x00000274
private void button1_Click(object sender, EventArgs e)
{string text = this.textBox1.Text;bool flag = text.Length != 34;if (flag){this.label1.Text = "你不是真ikun";}else{string a = text.Substring(0, 8);string a2 = text.Substring(8, 1);string a3 = text.Substring(9, 10);string b = text.Substring(19, 1);string a4 = text.Substring(20, 14);int num = 0;int num2 = 0;int num3 = 0;int num4 = 0;num = this.check1(a, num);num2 = this.check2(a3, num2);num3 = this.check3(a2, b, num3);num4 = this.check4(a4, num4);bool flag2 = num + num2 + num3 + num4 == 4;if (flag2){this.check5(text);}}
}
先判断flag长度是否等于34,然后会对输入的字符串分段分别经过check1,2,3,4函数进行检测,都通过时使用check5输出
check1:
public int check1(string a, int checkbox){string value = "3eabbb3900d553d7e98a154bffa4d24a";char[] array = a.ToCharArray();MD5 md = new MD5CryptoServiceProvider();byte[] bytes = Encoding.Default.GetBytes(a);byte[] array2 = md.ComputeHash(bytes);md.Clear();string text = "";for (int i = 0; i < array2.Length; i++){text += array2[i].ToString("x").PadLeft(2, '0');}bool flag = text.Equals(value);if (flag){this.label1.Text = "哇,珍德食你鸭!";checkbox = 1;}else{this.label1.Text = "你干嘛,嗨嗨呦!";checkbox = 0;}return checkbox;}
是一个md5加密,直接爆破解密,得到 1998-8-2
check2:
// Token: 0x0600000C RID: 12 RVA: 0x00002590 File Offset: 0x00000790public int check2(string a, int checkbox){string value = "ce143362813587af5af8592984c91b5a8c11b779";string text = "";SHA1 sha = new SHA1CryptoServiceProvider();byte[] bytes = Encoding.Default.GetBytes(a);byte[] array = sha.ComputeHash(bytes);sha.Clear();for (int i = 0; i < array.Length; i++){text += array[i].ToString("x").PadLeft(2, '0');}bool flag = text.Equals(value);if (flag){this.label1.Text = "哇,珍德食你鸭!";checkbox = 1;}else{this.label1.Text = "你干嘛,嗨嗨呦!";checkbox = 0;}return checkbox;
是一个sha1加密,解密得到 jinitaimei
check3:
// Token: 0x0600000D RID: 13 RVA: 0x0000264C File Offset: 0x0000084Cpublic int check3(string a, string b, int checkbox){string value = "-";bool flag = a.Equals(b) && a.Equals(value);if (flag){this.label1.Text = "哇,珍德食你鸭!";checkbox = 1;}else{this.label1.Text = "你干嘛,嗨嗨呦!";checkbox = 0;}return checkbox;}
直接判断是一个 '-'
check4:
// Token: 0x0600000E RID: 14 RVA: 0x000026AC File Offset: 0x000008ACpublic int check4(string a, int checkbox){string text = "7vKrvRh4Gu7wBQn7o9VfKQ==";byte[] bytes = Encoding.UTF8.GetBytes("pijinchengwangbankunyuanhang!!!!");byte[] bytes2 = Encoding.UTF8.GetBytes(a);ICryptoTransform cryptoTransform = new RijndaelManaged{Key = bytes,Mode = CipherMode.ECB,Padding = PaddingMode.PKCS7}.CreateEncryptor();byte[] array = cryptoTransform.TransformFinalBlock(bytes2, 0, bytes2.Length);string value = Convert.ToBase64String(array, 0, array.Length);bool flag = text.Equals(value);if (flag){this.label1.Text = "哇,珍德食你鸭!";checkbox = 1;}else{this.label1.Text = "你干嘛,嗨嗨呦!";checkbox = 0;}return checkbox;}
是一个AES加密.ECB,PKCS7,直接解密,得到:xiaoheizishiba
直接输入,得到flag(没想到直接输入....)
junk code
看wp知道是使用cheat engine工具
Cheat Engine工具使用:
- 首先运行程序
- 打开Cheat Engine工具,点击如下图标,查找Process,找到要调试的程序,打开
- 然后,可以在右边的框内输入要查找的字符串/字节
- 下面的数据右键->浏览相关内存区域,即可得到flag
方法二:直接使用ida动态调试
在ida中打开文件,动态调试
注意:一定要在此处,因为此处是字符串经过异或运算后的flag值
得到flag
奇怪的ELF
看了wp才知道是mov 混淆了
mov混淆问题:
MOV这种混淆是怎样产生的呢?剑桥大学的Stephen Dolan证明了x86的mov指令可以完成几乎所有功能了(可能还需要jmp),其他指令都是“多余的”。受此启发,有个大牛做了一个虚拟机加密编译器。它是一个修改版的LCC编译器,输入是C语言代码,输出的obj里面直接包含了虚拟机加密后的代码。如它的名字,函数的所有代码只有mov指令,没有其他任何指令。
这种题目的特征就是:汇编代码的汇编指令几乎全部就是MOV
1、 字符串的搜索是给我们最好的提示。
2、 MOV混淆是不会混淆函数的逻辑的。因此函数的逻辑还是不变的。
3、 大多数汇编代码的意思是可以猜测的。可以大概推测出具体操作了什么
具体mov混淆问题可以看:movfuscator混淆_Cherest_San的博客-CSDN博客
和这篇文章:浅析CTF中的反静态调试(二) - 先知社区
观察代码可以发现,flag的指令存储在R2中,直接手动搜索得到flag,search->text->R2。
Xor
直接搜索字符串,找到可疑字符串
设置断点,动态调试
一路F8,可以看到Please input flag,下面的异或部分
在此处创建函数
可以看到函数的主逻辑
__int64 v8; // rdi__int64 v9; // rax__int64 i; // rcx_QWORD *v11; // rax__int64 v13; // [rsp-1C8h] [rbp-1D8h]__int64 v14; // [rsp-1C0h] [rbp-1D0h]unsigned __int64 v15; // [rsp-1A0h] [rbp-1B0h]__int64 v16; // [rsp-198h] [rbp-1A8h]__int64 v17; // [rsp-190h] [rbp-1A0h]__int64 v18; // [rsp-188h] [rbp-198h]__int64 v19; // [rsp-180h] [rbp-190h]_QWORD v20[34]; // [rsp-158h] [rbp-168h]__int64 v21; // [rsp-48h] [rbp-58h]const char *v22; // [rsp-38h] [rbp-48h]_QWORD *v23; // [rsp-30h] [rbp-40h]void *v24; // [rsp-28h] [rbp-38h]char **v25; // [rsp-20h] [rbp-30h]while ( 1 ){v19 = a6;v15 = a4;v20[32] = v6;sub_81A060();v8 = sub_819800();a4 = v6;v6 = v8;if ( v19 + 1 >= v16 )break;a6 = v19 + 1;if ( v19 + 1 - ((v19 + 1) & 0xFFFFFFFFFFFFFFFCLL) >= 4 )sub_82EB60(v13, v14);}v21 = sub_819DA0();v17 = v8;*(&v13 - 2) = v7;v9 = sub_82F0E0();for ( i = 0LL; i < 32; ++i ){if ( v6 <= i )sub_82EB60(v13, v14);if ( v20[i] != *(unsigned __int8 *)(v9 + i) ){v18 = i;v14 = sub_85F300(v13);v9 = v21;i = v18;v6 = v17;}}v24 = &unk_875580;v25 = &off_8ABBB0;sub_861F60();v11 = (_QWORD *)sub_7DC740();*v11 = 0LL;v22 = "\b";v23 = v11;return sub_867420();
}
函数有两个循环,第一个循环时加密过程,第二个循环是对加密的明文进行判断,所以我们需要动态调试,过第一个循环,在第二个循环中
在此处先断点,随便输入什么跳过第一个循环,F8到第二个循环,拿到密文
写脚本解密
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){int i;char arr[]={0x3f,0x12,0x0,0x2,0x4,0xc,0x3d,0x42,0x3,0x28,0xc,0x1,0x2e,0x12,0x4,0x1,0x8,0x28,0x54,0x40,0x42,0x43,0x54,0x40,0x42,0x43,0x54,0x40,0x42,0x43,0x50,0xf};char key[]="qwer";for(i=0;i<40;i++){arr[i]=arr[i]^key[i%4];printf("%c",arr[i]);}return 0;
}
//Neepu{X0r_is_easy_1234123412345}