|
人物介绍: 小菜鸟:是个萌新 大佬远:是个黑阔
今天,小菜鸟苦思冥想,觉得肯定是因为字符串是直接写的,被大老远发现了,于是去学习了base64编码,首先利用万能的百度搜索相关知识,得到如下知识: 1)Base64使用A--Z,a--z,0--9,+,/ 这64个字符. 2)编码原理:将3个字节转换成4个字节( (3 X 8) = 24 = (4 X 6) )先读入3个字节,每读一个字节,左移8位,再右移四次,每次6位,这样就有4个字节了. 3)解码原理:将4个字节转换成3个字节.先读入4个6位(用或运算),每次左移6位,再右移3次,每次8位.这样就还原了. 于是小菜鸟又开始了编写程序。 1)桌面新建文件,还是命名为xcn,打开vscode,打开xcn文件夹,然后新建一个main.cpp文件。 2)然后新建一个json文件,运行配置用的,一会要在cmd窗口输入数据,点添加配置,按模板自动生成,然后根据情况进行修改: 3)接下来苦思冥想编写代码: #include <iostream> #include <cstring>
using namespace std;
int encodeBase64(const char *str, int strLen, char *cpystr, int cpystrLen) { //读取3个字节zxc,转换为二进制01111010 01111000 01100011 //转换为4个6位字节,011110 100111 100001 100011 //不足8位在前补0,变成00011110 00100111 00100001 00100011 //再将4个字节转换为十进制,30 39 33 35 //通过下标找到码表中对应的,e n h j //zxc加密后的密文就为,enhj //接下来第二轮加密,只剩1个字母v,转换成二进制01110110 //转换成2个6位字节,011101 100000(10不足6位末尾补0) //不足8位在前补0,变成 00011101 00100000 //转换成十进制,29 32 //通过下标找到码表中对应的d g,还缺两个才构成四字节,这时补等于号即可 //v加密后的密文为dg== //最后整个明文被base64加密完成,得到密文enhjdg== char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";//定义base64码表 int i = 0;//明文下标 int j = 0;//密文下标 while (i < strLen)//判断是否加密完毕 { if (j < cpystrLen - 1)//判断下标是否超过密文可存储范围 { if (i + 3 <= strLen)//读取到3个字节 { cpystr[j] = base64[str >> 2];//取第1个字节的前6位,将其加密为base64[]码表中对应的字符 cpystr[j + 1] = base64[(str & 3) << 4 | (str[i + 1] >> 4)];//取第一个字节的后2位再加上第二个字节的前4位,将其加密为base64[]码表中对应的字符 cpystr[j + 2] = base64[(str[i + 1] & 15) << 2 | (str[i + 2] >> 6)];//取第二个字节的后4位再加上第三个字节的前2位,将其加密为base64[]码表中对应的字符 cpystr[j + 3] = base64[str[i + 2] & 63];//取第三个字节的后6位,将其加密为base64[]码表中对应的字符 } else if (i + 2 <= strLen)//读取到2个字节 { cpystr[j] = base64[str >> 2];//取第1个字节的前6位,将其加密为base64[]码表中对应的字符 cpystr[j + 1] = base64[(str & 3) << 4 | (str[i + 1] >> 4)];//取第一个字节的后2位再加上第二个字节的前4位,将其加密为base64[]码表中对应的字符 cpystr[j + 2] = base64[(str[i + 1] & 15) << 2];//取第二个字节的后4位再加上第三个字节的前2位,将其加密为base64[]码表中对应的字符 //末尾补一个等于号 cpystr[j + 3] = '='; } else if (i + 1 <= strLen)//只读取到1个字节 { cpystr[j] = base64[str >> 2];//取第1个字节的前6位,将其加密为base64[]码表中对应的字符 cpystr[j + 1] = base64[(str & 3) << 4];//取第一个字节的后2位再加上第二个字节的前4位,将其加密为base64[]码表中对应的字符 //末尾补两个等于号 cpystr[j + 2] = '='; cpystr[j + 3] = '='; } else { cout << "为什么循环还在执行,程序逻辑错误!!!" << endl; return 1; } i += 3;//明文每次循环向后移动3位 j += 4;//密文每次循环向后移动4位 } else { cout << "存储密文的内存不足,请重新分配!!!" << endl; return 2; } } cpystr[j] = '\0';//补一个字符串结束符 return 0; }
int decodeBase64(const char *cpystr, int cpystrLen, char *str, int strLen) { //解密就是将加密的过程倒过来即可!
char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";//定义base64码表
int i = 0;//密文下标 int j = 0;//明文下标
while (i < cpystrLen)//判断是否解密完毕 { int index = 0;//码表下标 int temp1 = -1;//保存第一个密文下标 int temp2 = -1;//保存第二个密文下标 int temp3 = -1;//保存第三个密文下标 int temp4 = -1;//保存第四个密文下标
if (j < strLen - 1)//判断下标是否超过明文可存储范围 { //通过码表反查密文对应的下标,然后分别获得十进制数字 for (; index < 64; index++) { if (cpystr == base64[index]) { temp1 = index; } if (cpystr[i + 1] == base64[index]) { temp2 = index; } if (cpystr[i + 2] == base64[index]) { temp3 = index; } if (cpystr[i + 3] == base64[index])//一轮密文4个字节已取出,退出循环 { temp4 = index; }
//如果已经查到四个下标就退出循环! if (temp1 != -1 && temp2 != -1 && temp3 != -1 && temp4 != -1) break; }
if (temp3 != -1 && temp4 != -1)//完整的读取到了4个字节,直接解密 { str[j] = (temp1 << 2) | (temp2 >> 4);//取第一个密文6个字符再加上第二个密文前2个字符 str[j + 1] = ((temp2 & 15) << 4) | (temp3 >> 2);//取第二个密文后4个字符再加上第三个密文前4个字符 str[j + 2] = ((temp3 & 3) << 6) | temp4;//取第三个密文后2个字符再加上第四个密文6个字符 } else if (temp3 == -1)//只取到了2个字节 { str[j] = (temp1 << 2) | (temp2 >> 4);//取第一个密文6个字符再加上第二个密文前2个字符 j -= 2;//下标前移2位,不然补‘\0’的位置不对 } else if (temp4 == -1)//只取到了3个字节 { str[j] = (temp1 << 2) | (temp2 >> 4);//取第一个密文6个字符再加上第二个密文前2个字符 str[j + 1] = ((temp2 & 15) << 4 | (temp3 >> 2));//取第二个密文后4个字符第三个密文前4个字符 j--;//下标前移1位,不然补‘\0’的位置不对 } else { cout << "下标取值不对,程序逻辑错误!!!" << endl; return 1; }
i += 4;//密文每次循环向后移动4位 j += 3;//明文每次循环向后移动3位 } else { cout << "存储明文的内存不足,请重新分配!!!" << endl; return 2; } }
str[j] = '\0';//补一个字符串结束符 return 0; }
int main(int argc, char *argv[]) { /* 小菜鸟的第一个 C++ 程序 cmlnaHQh*/ char cpystr[20]; char str[20]; int cpystrLen = 0; int strLen = 20;
cout<<"Please input a password:"<<endl; cin>>cpystr;
cpystrLen = strlen(cpystr);
decodeBase64(cpystr, cpystrLen, str, strLen);
cout<<str<<endl;
return 0;
}
4)按下Ctrl+Shift+B生成exe程序,按下Ctrl+F5运行程序,编译通过。 5)输入cmlnaHQh,输出right!,嘿嘿,成功了!
小菜鸟拿着程序找到大佬远,看,我写的程序,输入密码就能输出right!,厉害不。这次你要是不知道密码,连right!都输出不了,有本事你再来试试。大佬远翻翻白眼,就这,等着,于是几分钟以后小菜鸟傻眼了,大佬远轻轻松松的得到了密码。 大佬远干了这事: 1)将程序拖进吾爱破解OD工具,下载地址:https://down.52pojie.cn/Tools/Debuggers/%E5%90%BE%E7%88%B1%E7%A0%B4%E8%A7%A3%E4%B8%93%E7%94%A8%E7%89%88Ollydbg.rar 2)然后在主界面右键-》中文搜索引擎-》智能搜索 3)看到了一行字符串ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/,会心一笑,原来是base64啊,先不轻举妄动,在提示输入密码的那一行回车打上断点,输入abcd: 4)可以看到拿到abcd字符串后进行了一个长度判断,接着进行了一系列的赋值操作,接着调用了4016E0函数,没有看到push参数传递,那么就肯定不是堆栈传参而是寄存器传参了,利用esp寄存器传参,F7进去这个call,可以看到先初始化了base64码表,接着不断的左移,右移运算,典型base64的编码的特征: 004016EC |. BB 98604000 mov ebx,main.00406098 ; ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
0040182C |. C1E0 02 |shl eax,0x2
00401834 |. C1F8 04 |sar eax,0x4
0040184A |. C1E0 04 |shl eax,0x4
00401852 |. C1F8 02 |sar eax,0x2
5)执行完这段代码后,回来发现是i?说明这可能是解码函数,也就是将输入的字符串进行base64解码,最终得到right,本来到这里拿着字符串加解密网站base64编码就得到密码了,但是我们会看中文搜索的时候有两个地方出现了base64码表,是不是一个编码一个解码用的呢?
6)重新加载程序,输入right!,在调用call main.004016E0的时候将它改成00401410,让他执行完这个函数,我们再来看看,是不是得到了cmlnaHQh密码呢。 |
使用道具 举报
使用道具 举报