文章目录
CrackMe1
运行CrackMe1.exe,提示 “嗯,对了” 代表成功。首先修改exe使得出现成功提示,其次不修改exe输入正确的密码达到成功的目的。
先打开CrackMe1.exe,看来是输入一个字符串得到正确答案的题:
(1)修改exe使得出现成功提示
i.用dnSpy修改CrackMe1.exe
用dnSpy打开CrackMe1.exe,反编译:
直接修改代码,将代码
“fOCPTVF0diO+B0IMXntkPoRJDUj5CCsT”==this.Encode(this.textBox1.Text)
中的相等==修改为不相等!=
这样只要我们输入错误的答案都能输出“嗯,对了。。”
结果果然输出了“嗯,对了。。”
ii.用IDA修改CrackMe1.exe
先用IDA打开CrackMe1.exe,
原本想通过字符串“嗯,对了。。”找到文件的关键位置
但发现可能因为是中文或是.Net弹窗的原因,反汇编中没有任何字符串。
只好查看出现的函数名称和各部分Names
找到了加密函数的入口位置:
点进去查看:
找到加密部分函数的中间代码MSIL 反汇编程序:
用Graph view来看逻辑更清楚
Ceq指令的意思就是判断前面的两个值相等就返回1,不相等就返回0。所以我们现在的目的就是修改ceq,改变它的返回值。双击ceq,定位到它的位置上去:
打开IDA显示指令对应的16进制机器码,将ceq对应的机器码:FE 01 修改成clt对应的机器码:FE 04
运行成功输出了“嗯,对了。。”:
iii.用ILDASM和ILASM修改CrackMe1.exe
先用ILDASM打开CrackMe1.exe
转储,保存为:
用编辑器打开:
将ceq跳转修改为clt跳转:
再用ILASM将.il文件编译成.exe文件。
成功输出了“嗯,对了。。”:
(2)不修改exe输入正确的密码达到成功的目的
先用.NET Reflector打开CrackMe1.exe。
将反编译出来的C#代码输出到本地:
因为虽然代码在Reflector上虽然已经有了,但是是以每个函数为单位的,输出到本地可以是整体的文件,可以更好的看出代码结构和逻辑:
我们可以看出来这个CrackMe1.exe主要的逻辑就是,将输入的字符串加密后与“fOCPTVF0diO+B0IMXntkPoRJDUj5CCsT”相等,就输出“嗯,对了。。”。
主要的就是这个加密函数:
所以我们只要将“fOCPTVF0diO+B0IMXntkPoRJDUj5CCsT”解密出需要输入的字符串即可。
C#源代码:
/*
* Created by SharpDevelop.
* User:
* Date:
* Time:
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Text;
using System.Collections;
using System.IO;
using System.Security.Cryptography;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
namespace Project
{
class Program
{
public static void Main(string[] args)
{
/*解密出的字符串*/
string result;
/*最后的加密字节数组*/
byte[] byte1 = Convert.FromBase64String("fOCPTVF0diO+B0IMXntkPoRJDUj5CCsT");
byte[] bytes = Encoding.ASCII.GetBytes("wctf{wol");
byte[] bytes2 = Encoding.ASCII.GetBytes("dy_crack}");
/*DES解密对象*/
DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider();
/*创建其支持存储区为内存的流*/
MemoryStream memoryStream = new MemoryStream();
/*将数据流链接到加密转换的流*/
CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateDecryptor(bytes, bytes2), CryptoStreamMode.Write);
/*将一个字节序列写入当前 CryptoStream,并将流中的当前位置提升写入的字节数*/
cryptoStream.Write(byte1, 0, byte1.Length);
/*用缓冲区的当前状态更新基础数据源或储存库,随后清除缓冲区。*/
cryptoStream.FlushFinalBlock();
/*将memoryStream对象序列化,从而将其中的对象值转换成byte[]*/
MemoryStream ms = new MemoryStream();
/*序列化接口IFormatter实例化二进制子类BinaryFormatter*/
IFormatter formatter = new BinaryFormatter();
/*转换成字节数组*/
formatter.Serialize(ms, memoryStream);
/*设置文本字符串的编码格式对象*/
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
/*将字节数组转换成字符串*/
result = encoding.GetString(memoryStream.GetBuffer());
/*输出解密后的字符串*/
Console.WriteLine(result);
/*等待读取任何一个键,输入任何一个键关闭输出屏,如果没有这一行,上面输出结果之后会马上关闭输出框*/
Console.ReadKey();
}
}
}
运行结果:
输出解密后的字符串为:wctf{dotnet_crackme1}
将它输入到原始CrackMe1.exe的输入框:
结果正确。