NewStar easygui re wp

NewStar easygui re wp

参考题解:NewStar CTF week4-CSDN博客

提示先去看消息机制:深入理解windows 消息机制_⒉消息队列发送消息,消息的标识可以从键盘获取,-CSDN博客大概看下

64位无壳

shift+f12没找到关键字符串,看看函数有个winmain点进去,都是些系统函数

发现sub_140001490不是点进去发现主要逻辑。

gui要注意MessageBox函数,一般这些函数就是解题的关键,比如点击verify就弹出了一个MessageBox

直接靠messagebox x交叉引用定位也行:

sub函数内部:

阅读代码

发现有个反调试器,一般碰见这种,我们需要直接nop或者jz改为jnz...这里我直接nop了

下面的逻辑就是

c 复制代码
        DlgItem = GetDlgItem(hWndParent, 101);
        WindowTextW = GetWindowTextW(DlgItem, String, 100);
        if ( WindowTextW <= 44 )
        {
          sub_140001000(String, (unsigned int)WindowTextW, v93);
          v12 = 0;
          if ( v93[1] == -57 )
            v12 = v93[0] == -33;
          v13 = 0;
          if ( v93[2] == 77 )
            v13 = v12;

可以理解,v93其实就是密文,这个代码那么长其实就是干校验密文

发现一个sub_140001000函数

WindowTextW<=44再对比下面的代码可以推测(也可以看sub_140001000内部推测),WindowTextW是密文长度44位(输入长度)

看sub_140001000内部

这段代码做的是给Src赋值,a1也就是上面的string每两个字节赋值给Src

每个元素占用2个字节,因此 a1 + 2 * i 表示第 i 个元素的地址。

然后加载v29 常量

最后将 Src[j] 的值作为索引,从 v29 数组中读取一个字节的数据,并将其存储回 Src[j] 中。

也就是说,我们也可以反过来根据Src去找v29的值,最后可能解密用到

下面是第一次加密:

紧接着两个dowhile

第一个dowhile 我们发现我们所输入的字符串应该是44长度,根本用不了Src[v19+303],这段我们可以先不关注

第二个dowhile 是对v29进行变形

再看到下面:

也就是加密过程是通过Src异或完成的

return (unsigned __int64)memcpy(a3, Src, v7);

我推测是要把Src赋值给a3也就是v93,后面动态调试也验证了

那么如何解出这道题?

我们可以用获取的密文(v93)去动态调试在程序运行到第一个dowhile循环的时候去替代Src

为什么这样做,因为第二次加密是个异或,我们再异或一次就得到第二次解密的完的密文,因为两个dowhile的操作都不影响Src(第一个Src操作影响不到,第二次是对v29的操作),我们可以直接到第一次加密处写解密代码。

下面下几个断点

输入aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

这里有一个坑点就是这个输入框输入的最大长度是42,但我们要输入44位,可以修改寄存器的值

改成2C:

运行到:

替换Src:

这里我用脚本,地址根据你自己的地址来

python 复制代码
# 导入IDA Python API
import ida_bytes

# 指定起始地址和字节数组
start_address = 0X000000E3CE76EB50
bytes_to_write = [
    0xdf, 0xc7, 0x4d, 0x14, 0xc1, 0xec, 0x08, 0xe4, 0x5f, 0x3f,
    0x03, 0xb4, 0x90, 0x4a, 0xb9, 0x8f, 0x8f, 0xfa, 0x71, 0x43,
    0xc7, 0xf1, 0x9d, 0xdd, 0x4f, 0xc0, 0x12, 0x44, 0x5c, 0x9d,
    0x88, 0x36, 0x2d, 0x16, 0x1d, 0xed, 0xbc, 0xef, 0xbb, 0x5b,
    0x9f, 0x77, 0xeb, 0x58
]

# 将字节逐个写入内存
for i, byte in enumerate(bytes_to_write):
    ida_bytes.patch_byte(start_address + i, byte)

print("Memory modification completed.")

得到第二次解密后的:

shift+e提出然后到第一次加密的地方写解密脚本

python 复制代码
v29 = [
  0x31, 0x74, 0x54, 0x20, 0x03, 0x53, 0x78, 0x70, 0x3A, 0x35,
  0x65, 0x42, 0x04, 0x6B, 0x1F, 0x43, 0x06, 0x37, 0x00, 0x76,
  0x21, 0x08, 0x0B, 0x13, 0x52, 0x4B, 0x2F, 0x1A, 0x59, 0x2C,
  0x56, 0x51, 0x7F, 0x3B, 0x0E, 0x05, 0x26, 0x15, 0x25, 0x63,
  0x64, 0x7A, 0x3C, 0x29, 0x41, 0x2A, 0x12, 0x17, 0x2E, 0x39,
  0x57, 0x3D, 0x66, 0x33, 0x44, 0x6C, 0x6F, 0x47, 0x16, 0x71,
  0x5F, 0x1C, 0x14, 0x5A, 0x0C, 0x4F, 0x01, 0x30, 0x1B, 0x68,
  0x0F, 0x62, 0x3F, 0x18, 0x69, 0x6D, 0x7E, 0x5D, 0x6A, 0x28,
  0x22, 0x5B, 0x55, 0x72, 0x09, 0x5E, 0x02, 0x3E, 0x50, 0x7B,
  0x46, 0x45, 0x38, 0x10, 0x48, 0x79, 0x60, 0x36, 0x61, 0x6E,
  0x2D, 0x49, 0x7C, 0x2B, 0x34, 0x27, 0x11, 0x7D, 0x0D, 0x0A,
  0x77, 0x73, 0x58, 0x5C, 0x4C, 0x32, 0x4D, 0x1E, 0x24, 0x40,
  0x67, 0x4A, 0x4E, 0x1D, 0x07, 0x75, 0x19, 0x23, 0xA0, 0xF4,
  0x8F, 0xF8, 0x30
]

Src = [
  0x6F, 0x81, 0xA6, 0xC5, 0x63, 0xAC, 0x4B, 0xC7, 0x8F, 0x29,
  0x87, 0xA4, 0x27, 0xAA, 0xA6, 0x69, 0x4F, 0x27, 0xAE, 0xEC,
  0x27, 0x2E, 0xE7, 0xA9, 0x69, 0x87, 0x2E, 0xE5, 0x2F, 0x24,
  0xE6, 0x6F, 0x44, 0x87, 0xA9, 0x89, 0x4F, 0x26, 0x47, 0x21,
  0xAB, 0x01, 0xA7, 0xAE
]

enc = [
  0xdf, 0xc7, 0x4d, 0x14, 0xc1, 0xec, 0x8, 0xe4, 0x5f, 0x3f,
           0x3, 0xb4, 0x90, 0x4a, 0xb9, 0x8f, 0x8f, 0xfa, 0x71, 0x43,
           0xc7, 0xf1, 0x9d, 0xdd, 0x4f, 0xc0, 0x12, 0x44, 0x5c, 0x9d,
           0x88, 0x36, 0x2d, 0x16, 0x1d, 0xed, 0xbc, 0xef, 0xbb, 0x5b,
           0x9f, 0x77, 0xeb, 0x58
]

for k in range(0, 44, 4):
  a = Src[k]
  b = Src[k + 1]
  c = Src[k + 2]
  d = Src[k + 3]
  Src[k + 3] = ((a >> 5) & 0x7) | ((d << 3) & 0xf8)
  Src[k + 2] = ((d >> 5) & 0x7) | ((c << 3) & 0xf8)
  Src[k + 1] = ((c >> 5) & 0x7) | ((b << 3) & 0xf8)
  Src[k] = ((b >> 5) & 0x7) | ((a << 3) & 0xf8)

# 这个上面讲了
for i in range(len(Src)):
    print(chr(v29.index(Src[i])),end='')

print()

for i in range(44):
    print('a',end='')

这个解密很容易踩坑,我第一次写就踩了

比如Src[k+3] = ((a>>5) & 0x7) | ((d<<3)&0xf8),原来的加密中是

c 复制代码
    for ( k = 0i64; k < v4; k += 4i64 )
    {
      v11 = Src[k + 3];
      v12 = Src[k + 2];
      v13 = ((unsigned __int8)Src[k] >> 3) | (32 * v11);
      v14 = 32 * Src[k + 1];
      Src[k + 1] = (32 * Src[k]) | ((unsigned __int8)Src[k + 1] >> 3);
      v15 = 32 * v12;
      Src[k + 2] = v14 | HIBYTE(v15);
      Src[k] = v13;
      Src[k + 3] = v15 | (v11 >> 3);
    }

Src[k+3]由v15和v11组成也就是Src[k+3]和Src[k+2]因此我写出了Src[k+3] = ((c>>5) & 0x7) | ((d<<3)&0xf8)这样的代码,实际是错的

因为其实原来的加密的意思是Src[k+3]由Src[k+2]的低5位和Src[k+3]的高3位组成,Src[k]由Src[k+3]的低5位和Src[k]的高3位组成

那么我们要还原Src[k+3]也就是由rc[k+3]的高3位和Src[k+3]的低5位拼接,这样才是正确的

这里解密写成这样也行:

python 复制代码
for k in range(0, 44, 4):
  a = Src[k]
  b = Src[k + 1]
  c = Src[k + 2]
  d = Src[k + 3]
  Src[k + 3] = ((a >> 5) & 0xff) | ((d << 3) & 0xff)
  Src[k + 2] = ((d >> 5) & 0xff) | ((c << 3) & 0xff)
  Src[k + 1] = ((c >> 5) & 0xff) | ((b << 3) & 0xff)
  Src[k] = ((b >> 5) & 0xff) | ((a << 3) & 0xff)
复制代码
0x7是低三位的意思,0x8f也差不多

全用0xff因为与的目的其实跟mod 256差不多,因为向高位移位的话如果不与可能会把高位的也搞进去比如

1111 0000 << 3 为 111 1000 0000其实我们最大是8位,但是|的时候不做处理会把高位也放进去

得到也是flag{GU!_r3v3R5e_3nG1n3er1ng_i5_v3ry_s1mpl3}

b >> 5) & 0xff) | ((a << 3) & 0xff)

复制代码
> ```
> 0x7是低三位的意思,0x8f也差不多
> ```

全用0xff因为与的目的其实跟mod 256差不多,因为向高位移位的话如果不与可能会把高位的也搞进去比如

1111 0000 << 3 为 111 1000 0000其实我们最大是8位,但是|的时候不做处理会把高位也放进去

得到也是flag{GU!_r3v3R5e_3nG1n3er1ng_i5_v3ry_s1mpl3}

**这道题很质量**
相关推荐
用户962377954487 小时前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机10 小时前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机10 小时前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户9623779544811 小时前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star11 小时前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户9623779544815 小时前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher2 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
一次旅行5 天前
网络安全总结
安全·web安全
red1giant_star5 天前
手把手教你用Vulhub复现ecshop collection_list-sqli漏洞(附完整POC)
安全
ZeroNews内网穿透5 天前
谷歌封杀OpenClaw背后:本地部署或是出路
运维·服务器·数据库·安全