2019年1月16日星期三
任务一、运行CrackMe1.exe,提示 "嗯,对了" 代表成功。首先修改exe使得出现成功提示,其次不修改exe输入正确的密码达到成功的目的。
hint:https://blog.csdn.net/Nagi_Way/article/details/68961121
使用.Net的Reflector反编译器,使用F3查找该函数
byte[] bytes = Encoding.ASCII.GetBytes("wctf{wol");
byte[] rgbIV = Encoding.ASCII.GetBytes("dy_crack}");
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
int keySize = provider.KeySize;
MemoryStream stream = new MemoryStream();
CryptoStream stream2 = new CryptoStream(stream, provider.CreateEncryptor(bytes, rgbIV), CryptoStreamMode.Write);
StreamWriter writer = new StreamWriter(stream2);
writer.Write(data);
writer.Flush();
stream2.FlushFinalBlock();
writer.Flush();
return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length);
密文:fOCPTVF0diO+B0IMXntkPoRJDUj5CCsT
密钥:wctf{wol
偏移量:dy_crack}
明文:wctf{dotnet_crackme1}
任务二、阅读下面文章,写出阅读心得
http://www.vuln.cn/7115
http://www.vuln.cn/7116
http://www.vuln.cn/7117
http://www.vuln.cn/7118
博客一:
1、JVM字节码比其他的X86低级代码更加容易反编译
1)多很多相关类型的信息
2)JVM(java虚拟机)内存模式更加严格和概括
3)Java编译器没有做任何优化工作(JAM JIT不是实时)
2、JVM知识何时有用?
1)分析混淆代码
2)创建自己的混淆器
3)创造编译器代码生成器
3、javap –c 反编译器
1)通过编译确定内存申请状况
编译:
Int i=2;
Int j=3;
Code:
0: iconst_2 //把2放到栈顶
1: istore_1 //把栈顶的值放到局部变量1中,即i中
2: iconst_3 //把3放到栈顶
3: istore_2 //把栈顶的值放到局部变量1中,即j中
4: return
编译:
Int i=2;
Int j=2;
Code:
0: iconst_2 //把2放到栈顶
1: istore_1 //把栈顶的值放到局部变量1中,即i中
2: iconst_2 //把2放到栈顶
3: istore_2 //把栈顶的值放到局部变量2中,即j中(i 和 j同时指向2)
4: return
编译:
Int i=2;
Int j=i;
Code:
0: iconst_2 //把2放到栈顶
1: istore_1 //把栈顶的值放到局部变量1中,即i中
2: iload_1 //把i的值放到栈顶,也就是说此时栈顶的值是2
3: istore_2 //把栈顶的值放到局部变量2中,即j中
4: return
2)通过编译确定i++与++i的区别与联系
Int i=1; I++;
Int j=1; J++
Code:
0: iconst_1
1: istore_1
2: iinc 1, 1 //这个个指令,把局部变量1,也就是i,增加1,这个指令不会导致栈的变 化,i此时变成2了
5: iconst_1
6: istore_2
7: iinc 2, 1//这个个指令,把局部变量2,也就是j,增加1,这个指令不会导致栈的变化,j此时变成2了
10: return
Int i=1; I++;
Int j=1; ++J;
Code:
0: iconst_1
1: istore_1
2: iload_1
3: iinc 1, 1 //局部变量1(即i)加1变为2,注意这时栈中仍然是1,没有改变
6: istore_1 //把栈顶的值放到局部变量1中,即i这时候由2变成了1
7: iconst_1
8: istore_2
9: iinc 2, 1 //局部变量2(即j)加1变为2,注意这时栈中仍然是1,没有改变
12: iload_2 //把局部变量2(即j)的值放到栈顶,此时栈顶的值变为2
13: istore_2 //把栈顶的值放到局部变量2中,即j这时候真正由1变成了2
14: return
理解了上面的程序,我们来看一个很有趣的程序:
public class a{
public static void main(String[] args){
int m=0;
for(int i=0;i<100;i++)
m=m++;
System.out.println(m);
}
}
先看结果:
是不是很惊艳!至少我被惊艳了!
当执行m=m++的时候m的值加一了,但是栈中的值还是0
Python中是没有i++的
Java的i++输出为0
C的i++输出是100
证明参考博客:
http://www.cnblogs.com/beautiful-code/p/6424977.html
https://www.cnblogs.com/tutuu/p/4115172.html
https://blog.csdn.net/qq_37937537/article/details/79931157
证明如下:
【这里有图片无法上传,便不再上传,感兴趣同学自行研究】
程序如下:
m++的:
Code:
0: iconst_0 //把0放到栈顶
1: istore_1 //把栈顶元素放到1号存储块中,即为m=0
2: iconst_0 //把0放到栈顶
3: istore_2 //把栈顶元素放到1号存储块中,即为i=0
4: iload_2 //把局部变量2(m)放到栈顶
5: bipush 100 //循环100次
7: if_icmpge 19
10: iinc 1, 1 //把局部变量1加一,m++
13: iinc 2, 1 //把局部变量2加一,i++
16: goto 4 //前往4号地址块
19: getstatic // Field java/lang/System.out:Ljava/io/PrintStream;
22: iload_1
23: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
m=m++的:
Code:
0: iconst_0 //把0放到栈顶
1: istore_1 //把栈顶元素放到局部变量表第1个位置中,即为m=0
2: iconst_0 //把0放到栈顶
3: istore_2 //把栈顶元素放到局部变量表第2个位置号中,即为i=0
4: iload_2 //复制变量2入栈
5: bipush 100 //循环100次
7: if_icmpge 21
10: iload_1 //m++
11: iinc 1, 1
14: istore_1 重点//将命令10的结果赋给变量1,组合命令,勿单看
15: iinc 2, 1 //i++
18: goto 4 //跳转到4
21: getstatic // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_1
25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
28: return