首页
社区
课程
招聘
[原创]CTF2017 第十一题 ToBeBetterCrackMe
发表于: 2017-6-22 21:50 3303

[原创]CTF2017 第十一题 ToBeBetterCrackMe

2017-6-22 21:50
3303

本章主要说一些重点逻辑,记录坑点,囧,我居然在 伪模式 解无解数学题花了不少时间。

查找引用则找到重要函数。(括号笑

函数主要过程

附解密该函数及求 x y 脚本,在壳程序的 IDA 运行

最后的解密函数比较变态,只能自己看没有啥技巧,我找到了原型代码,题目中是用的这个版本的变种,附上补丁,即可生成内置字符串的加密结果



图1
图1
import idaapi
import struct
# 壳文件的 0x41000 前2个整数
src = [0x83F08EA7, 0x3F0FBA29]
# 主文件的 0x340B0 存正确结果片段,前2个整数
dst = [0x1070EC81, 0x55530000]
# 枚举 y 爆破,因为反向异或 求x 的结果很大机率就是最低位字节不一样,高位一般都一样
for y in xrange(256):
    if (((((src[0] + 0x1010101 * y) & 0xFFFFFFFF) ^ dst[0]) & 0xFFFFFF00) ==
        ((((src[1] + 0x1010101 * y) & 0xFFFFFFFF) ^ dst[1]) & 0xFFFFFF00)):
        print "y:", hex(y)
        break
x = ((src[0] + 0x1010101 * y) & 0xFFFFFFFF) ^ dst[0]
print "x:", hex(x)
base = 0x441000
for i in xrange(0x5000/4):
    t = idaapi.get_many_bytes(base + i*4, 4)
    b = struct.unpack("<I", t)[0]
    b = ((b + 0x1010101 * y) & 0xFFFFFFFF) ^ (x + i)
    t = struct.pack("<I", b)
    idaapi.put_many_bytes(base + i*4, t)
--- Des.cpp	2017-06-22 21:29:47.000000000 +0800
+++ Des2.cpp	2017-06-22 21:45:03.000000000 +0800
@@ -6,7 +6,7 @@
 */
 //////////////////////////////////////////////////////////////////////////
 
-#include "memory.h"
+#include <string.h>
 #include "Des.h"
 
 //////////////////////////////////////////////////////////////////////////
@@ -155,7 +155,15 @@
 {
     static bool M[64], tmp[32], *Li=&M[0], *Ri=&M[32];
     ByteToBit(M, In, 64);
+    if (!Type) {
+        for (int i=0; i<128; ++i) {
+            if (i % 2==0) {
+                M[i] = !M[i];
+            }
+        }
+    }
     Transform(M, M, IP_Table, 64);
+
     if( Type == ENCRYPT ){
         for(int i=0; i<16; ++i) {
             memcpy(tmp, Ri, 32);
@@ -163,7 +171,13 @@
             Xor(Ri, Li, 32);
             memcpy(Li, tmp, 32);
         }
+        memcpy(tmp, M, 32);
+        memcpy(M, M+32, 32);
+        memcpy(M+32, tmp, 32);
     }else{
+        memcpy(tmp, M, 32);
+        memcpy(M, M+32, 32);
+        memcpy(M+32, tmp, 32);
         for(int i=15; i>=0; --i) {
             memcpy(tmp, Li, 32);
             F_func(Li, (*pSubKey)[i]);
@@ -172,6 +186,14 @@
         }
 	}
     Transform(M, M, IPR_Table, 64);
+    if (Type) {
+        for (int i=0; i<128; ++i) {
+            if (i % 2==0) {
+                M[i] = !M[i];
+            }
+        }
+    }
+
     BitToByte(Out, M, 64);
 }
 void SetSubKey(PSubKey pSubKey, const char Key[8])
@@ -220,14 +242,18 @@
 }
 void ByteToBit(bool *Out, const char *In, int bits)
 {
+    int t = bits - 1;
+    if (t > 7) t = 7;
     for(int i=0; i<bits; ++i)
-        Out[i] = (In[i>>3]>>(i&7)) & 1;
+        Out[i] = (In[i>>3]>>(t-i%8))&1;
 }
 void BitToByte(char *Out, const bool *In, int bits)
 {
+    int t = bits - 1;
+    if (t > 7) t = 7;
     memset(Out, 0, bits>>3);
     for(int i=0; i<bits; ++i)
-        Out[i>>3] |= In[i]<<(i&7);
+        Out[i>>3] |= In[i]<<(t-i%8);
 }
 //////////////////////////////////////////////////////////////////////////
 // Code ends at Line 231
  • CreateFile 打开自身(确保是原始文件)
  • VirtualAlloc 申请 0x5000 可执行 buf
  • SetFilePointer seek 文件到偏移 0x41000
  • ReadFile 0x5000 字节到 buf
  • 将输入的前8个字符解 hex 到 uint32 x
  • 将接下来两个字符解 hex 到 uint8 y
  • 用 x 和 y 解密 buf 中的代码
  • 用 0x4340B0 的正确代码片段 比较 buf 前96个字节
  • 用 buf 中的代码解密剩余输入,结果为 内置字符 则注册成功
  1. 明天要早起,今天就少写点
  2. 我觉得这题着重考的是调试能力,我调试能力不过关,导致我根本无法调试程序开启新线程后运行的一系列逻辑,不知道咋回事,等结束去翻别人 WP
  3. 既然调试不了的话,我基本全程是在 IDA 上看过的,所以本文只给出程序的基本过程
  1. 壳程序一开始会解出一个主程序覆盖自身映射区,用仿 win 加载器内部加载后跳入入口点执行
  2. 只要 dump 出内存,0x400000~0x445000,先用 LordPE 修改区段物理基址和虚拟基址一致,然后用 ImportREC 填入 OEP 0x18356 即可修复导入表
  1. 我是无意中找到的,在分析 私有API 的 MyGetProcAddress 函数时候,发现有个字符串可疑
  1. 查找引用则找到重要函数。(括号笑

  2. 函数主要过程

    • CreateFile 打开自身(确保是原始文件)
    • VirtualAlloc 申请 0x5000 可执行 buf
    • SetFilePointer seek 文件到偏移 0x41000
    • ReadFile 0x5000 字节到 buf
    • 将输入的前8个字符解 hex 到 uint32 x
    • 将接下来两个字符解 hex 到 uint8 y
    • 用 x 和 y 解密 buf 中的代码
    • 用 0x4340B0 的正确代码片段 比较 buf 前96个字节
    • 用 buf 中的代码解密剩余输入,结果为 内置字符 则注册成功
  3. 附解密该函数及求 x y 脚本,在壳程序的 IDA 运行

    import idaapi
    import struct
    # 壳文件的 0x41000 前2个整数
    src = [0x83F08EA7, 0x3F0FBA29]
    # 主文件的 0x340B0 存正确结果片段,前2个整数
    dst = [0x1070EC81, 0x55530000]
    # 枚举 y 爆破,因为反向异或 求x 的结果很大机率就是最低位字节不一样,高位一般都一样
    for y in xrange(256):
        if (((((src[0] + 0x1010101 * y) & 0xFFFFFFFF) ^ dst[0]) & 0xFFFFFF00) ==
            ((((src[1] + 0x1010101 * y) & 0xFFFFFFFF) ^ dst[1]) & 0xFFFFFF00)):
            print "y:", hex(y)
            break
    x = ((src[0] + 0x1010101 * y) & 0xFFFFFFFF) ^ dst[0]
    print "x:", hex(x)
    base = 0x441000
    for i in xrange(0x5000/4):
        t = idaapi.get_many_bytes(base + i*4, 4)
        b = struct.unpack("<I", t)[0]
        b = ((b + 0x1010101 * y) & 0xFFFFFFFF) ^ (x + i)
        t = struct.pack("<I", b)
        idaapi.put_many_bytes(base + i*4, t)

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//