ReversingKr-wp(5)

AutoHotkey1

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

AuthKey = un_md5(DecryptKey) + " " + un_md5(EXE's Key)

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Ex:)
 DecryptKey = 1dfb6b98aef3416e03d50fd2fb525600
 EXE's  Key = c944634550c698febdd9c868db908d9d
 => AuthKey = visual studio

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

By Pyutic

需要在二进制文件中找到两个MD5值
查壳发现有UPX, 脱掉之后运行会报错, 估计是有自校验机制, 所以采用动调, 一路跟踪定位到弹窗函数

int __thiscall sub_4508C7(FILE **this, int a2, char *Str)
{
  FILE *v4; // eax
  int i; // eax
  signed int v7; // eax
  signed int j; // edx
  int v9; // eax
  int k; // eax
  int l; // eax
  int v12; // edi
  int v13; // edi
  int v14; // ecx
  FILE *v15; // [esp-24h] [ebp-570h]
  int v16; // [esp-4h] [ebp-550h]
  char v17[1028]; // [esp+Ch] [ebp-540h] BYREF
  CHAR Filename[264]; // [esp+410h] [ebp-13Ch] BYREF
  char v19[32]; // [esp+518h] [ebp-34h] BYREF
  int v20; // [esp+538h] [ebp-14h] BYREF
  int Buffer; // [esp+53Ch] [ebp-10h] BYREF
  int v22; // [esp+540h] [ebp-Ch] BYREF
  int v23; // [esp+544h] [ebp-8h]
  char v24; // [esp+54Bh] [ebp-1h] BYREF
  char *Stra; // [esp+558h] [ebp+Ch]

  sub_450F56(v17);
  GetModuleFileNameA(0, Filename, 0x104u);
  v4 = fopen(Filename, aRb);
  *this = v4;
  if ( !v4 )
    return 1;
  for ( i = 0; i < 8; ++i )
  {
    v19[i + 16] = byte_466514[i];
    v19[i + 24] = byte_46650C[i];
  }
  v7 = strlen(Str);
  this[68] = 0;
  for ( j = 0; j < v7; ++j )
    this[68] = (FILE *)((char *)this[68] + Str[j]);
  fseek(*this, -8, 2);
  fread(this + 1, 4u, 1u, *this);
  v9 = ftell(*this);
  v15 = *this;
  v23 = v9;
  fread(&Buffer, 4u, 1u, v15);
  fseek(*this, 0, 0);
  Stra = 0;
  for ( k = 0; (int)Stra < v23; ++Stra )
  {
    if ( ((*this)->_flag & 0x10) != 0 )
      break;
    fread(&v20, 1u, 1u, *this);
    k = sub_450F95(v20);
  }
  if ( Buffer != (k ^ 0xAAAAAAAA) )
    goto LABEL_16;
  fseek(*this, (int)this[1], 0);
  if ( !fread(v19, 0x10u, 1u, *this) )
    goto LABEL_16;
  for ( l = 0; l < 16; ++l )
  {
    if ( v19[l] != v19[l + 16] )
      break;
  }
  if ( l != 16 )
  {
LABEL_16:
    v16 = 3;
LABEL_19:
    v12 = v16;
    fclose(*this);
    return v12;
  }
  fread(&v24, 1u, 1u, *this);
  if ( v24 != 3 )
  {
    v16 = 4;
    goto LABEL_19;
  }
  fread(&v22, 4u, 1u, *this);
  v13 = v22 ^ 0xFAC1;
  fread(this + 3, 1u, v22 ^ 0xFAC1, *this);
  sub_450ABA(this + 3, v13, v13 + 50130);
  *((_BYTE *)this + v13 + 12) = 0;
  v14 = 0;
  for ( this[68] = 0; v14 < v13; ++v14 )
    this[68] = (FILE *)((char *)this[68] + *((char *)this + v14 + 12));
  this[2] = (FILE *)ftell(*this);
  return 0;
}

函数会经过一堆复杂操作, 一连串文件读写懒得逆, 主要是观察到函数最后会产生MD5值, 直接用不脱壳的原程序调试确定sub_450ABA返回的MD5值, 这里必须用硬件断点, 因为解密过程会涉及代码自身运算, 如果用内存断点会修改数据导致解密出错, hardware breakpoint下断以后直接F9就到了(懒人逆向法

在这里插入图片描述

第一个MD5是220226394582d7117410e3c021748c2a
第二个MD5也有懒人法得到, 结合Autohotkey是一种脚本引擎, 可以把脚本转化为exe, 也自然有将exe逆回脚本的工具: https://www.autohotkey.com/download/Exe2Ahk.exe

Exe2Ahk.exe ahk.exe <password>
解出来就能得到第二个MD5, 两个解密一下拼接就是flag

CSHOP

打开什么都没有…
在这里插入图片描述
看题目CSHOP和C#谐音, 暗示.net逆向, 用dnspy打一套

		private void InitializeComponent()
		{
			ComponentResourceManager componentResourceManager = new ComponentResourceManager(typeof(FrmMain));
			this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD = new Button();
			this.lbl\u007F\u000A = new Label();
			this.lbl\u007F\u000D = new Label();
			this.lbl\u007F\u0014 = new Label();
			this.lbl\u007F\u0015 = new Label();
			this.lbl\u007F\u0011 = new Label();
			this.lbl\uFFFD\u0014 = new Label();
			this.lbl\u007F\u0019 = new Label();
			this.lbl\u007F\u0001 = new Label();
			this.lbl\u007F\u0003 = new Label();
			this.lbl\u007F\u0002 = new Label();
			base.SuspendLayout();
			this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.Location = new Point(165, 62);
			this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.Name = "btnStart";
			this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.Size = new Size(0, 0);
			this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.TabIndex = 0;
			this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.UseVisualStyleBackColor = true;
			this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.Click += this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD_Click;
			this.lbl\u007F\u000A.Location = new Point(43, 123);
			this.lbl\u007F\u000A.Name = "lblGu";
			this.lbl\u007F\u000A.Size = new Size(53, 23);
			this.lbl\u007F\u000A.TabIndex = 1;
			this.lbl\u007F\u000A.Text = "label1";
			this.lbl\u007F\u000D.Location = new Point(90, 123);
			this.lbl\u007F\u000D.Name = "lblNu";
			this.lbl\u007F\u000D.Size = new Size(53, 23);
			this.lbl\u007F\u000D.TabIndex = 2;
			this.lbl\u007F\u000D.Text = "label2";
			this.lbl\u007F\u0014.Location = new Point(135, 123);
			this.lbl\u007F\u0014.Name = "lblSu";
			this.lbl\u007F\u0014.Size = new Size(53, 23);
			this.lbl\u007F\u0014.TabIndex = 3;
			this.lbl\u007F\u0014.Text = "label3";
			this.lbl\u007F\u0015.Location = new Point(182, 123);
			this.lbl\u007F\u0015.Name = "lblTu";
			this.lbl\u007F\u0015.Size = new Size(53, 23);
			this.lbl\u007F\u0015.TabIndex = 4;
			this.lbl\u007F\u0015.Text = "label4";
			this.lbl\u007F\u0011.Location = new Point(228, 123);
			this.lbl\u007F\u0011.Name = "lblKu";
			this.lbl\u007F\u0011.Size = new Size(53, 23);
			this.lbl\u007F\u0011.TabIndex = 5;
			this.lbl\u007F\u0011.Text = "label4";
			this.lbl\uFFFD\u0014.Location = new Point(278, 123);
			this.lbl\uFFFD\u0014.Name = "ppppp";
			this.lbl\uFFFD\u0014.Size = new Size(53, 23);
			this.lbl\uFFFD\u0014.TabIndex = 6;
			this.lbl\uFFFD\u0014.Text = "label4";
			this.lbl\u007F\u0019.Location = new Point(324, 123);
			this.lbl\u007F\u0019.Name = "lblMu";
			this.lbl\u007F\u0019.Size = new Size(53, 23);
			this.lbl\u007F\u0019.TabIndex = 7;
			this.lbl\u007F\u0019.Text = "label4";
			this.lbl\u007F\u0001.Location = new Point(369, 123);
			this.lbl\u007F\u0001.Name = "lblXu";
			this.lbl\u007F\u0001.Size = new Size(53, 23);
			this.lbl\u007F\u0001.TabIndex = 8;
			this.lbl\u007F\u0001.Text = "label4";
			this.lbl\u007F\u0003.Location = new Point(413, 123);
			this.lbl\u007F\u0003.Name = "lblZu";
			this.lbl\u007F\u0003.Size = new Size(53, 23);
			this.lbl\u007F\u0003.TabIndex = 9;
			this.lbl\u007F\u0003.Text = "label4";
			this.lbl\u007F\u0002.Location = new Point(457, 123);
			this.lbl\u007F\u0002.Name = "lblQu";
			this.lbl\u007F\u0002.Size = new Size(53, 23);
			this.lbl\u007F\u0002.TabIndex = 10;
			this.lbl\u007F\u0002.Text = "label4";
			base.AutoScaleDimensions = new SizeF(7f, 12f);
			base.AutoScaleMode = AutoScaleMode.Font;
			base.ClientSize = new Size(626, 316);
			base.Controls.Add(this.lbl\u007F\u0002);
			base.Controls.Add(this.lbl\u007F\u0003);
			base.Controls.Add(this.lbl\u007F\u0001);
			base.Controls.Add(this.lbl\u007F\u0019);
			base.Controls.Add(this.lbl\uFFFD\u0014);
			base.Controls.Add(this.lbl\u007F\u0011);
			base.Controls.Add(this.lbl\u007F\u0015);
			base.Controls.Add(this.lbl\u007F\u0014);
			base.Controls.Add(this.lbl\u007F\u000D);
			base.Controls.Add(this.lbl\u007F\u000A);
			base.Controls.Add(this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD);
			base.FormBorderStyle = FormBorderStyle.FixedSingle;
			base.Icon = (Icon)componentResourceManager.GetObject("$this.Icon");
			base.MaximizeBox = false;
			base.Name = "FrmMain";
			base.StartPosition = FormStartPosition.CenterScreen;
			this.Text = "CSHOP";
			base.Load += this.Form1_Load;
			base.ResumeLayout(false);
		}

找到基本模块, 发现有button, 但是实际运行时没有, 观察属性, 发现

this.\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.Size = new Size(0, 0);

可能是button被改没了, 手动修改size保存
在这里插入图片描述
在这里插入图片描述

得到exe, 运行
在这里插入图片描述

在这里插入图片描述

PEPassword

original.exe里是虚晃的password, 先不管, 拿packed.exe查壳
在这里插入图片描述

调试定位主体逻辑, 这里是调用库函数dispatchMessageA处理输入的字符
在这里插入图片描述
在IDA中查看对应的cmp指令的交叉引用
在这里插入图片描述
OD中查看0x004091A8地址, 提前到基本块入口下断调试发现ESI中会保存输入的字符串
在这里插入图片描述

调整EAX == 0xE98F842A越过判断条件继续跟, 发现会进入EndDialog终止程序, 返回去看可以确定核心校验函数就是sub_004091D8, 对比一下original.exe的401000地址是入口, packed之后应该是加密了二进制程序, 所以综合起来看整个题目的意思就是找到packed.exe的正确输入然后解密出入口地址开始的函数, 对应到original.exe即输出password的函数打印出flag
分析解密函数

__int64 __usercall sub_409200@<edx:eax>(__int64 a1@<edx:eax>)
{
  __int64 v1; // rdi
  int v2; // eax
  int v3; // ebx
  int v4; // eax
  unsigned int v5; // ecx
  unsigned int v6; // edx
  int v7; // ebx
  __int64 v9; // [esp-20h] [ebp-20h]

  v9 = a1;
  v1 = a1;
  LODWORD(a1) = 'HASH';
  LOBYTE(a1) = *(_BYTE *)HIDWORD(a1) ^ 'H';
  v2 = sub_4091DA(a1, SHIDWORD(a1));
  v3 = v2;
  BYTE1(v2) ^= *(_BYTE *)HIDWORD(v1);
  v4 = sub_4091DA(v2, SHIDWORD(v1));
  v6 = v5 >> 2;
  do
  {
    *(_DWORD *)v1 ^= v4;
    LODWORD(v1) = v1 + 4;
    v7 = __ROL4__(v3, v4);
    v4 = __ROR4__(v7 ^ v4, SBYTE1(v7));
    v3 = v4 + v7;
    --v6;
  }
  while ( v6 );
  return v9;
}

在这里插入图片描述

根据401000地址处已知的原数据, 和加密后的packed的数据, 可以得到第一轮v4的值, 对于v3的值可以爆破32bits, 结合第二轮v4的值为0x5a5a7e05

#include <stdio.h>

unsigned int rol(unsigned int data, char bits) {
	return (unsigned int)(data<<bits)|(data>>(32-bits));
}

unsigned int ror(unsigned int data, char bits) {
	return (unsigned int)(data>>bits)|(data<<(32-bits));
}

int main() {
	unsigned int original = 0x014cec81 ^ 0x0B6E62E17;
	unsigned int target = 0x5a5a7e05;
	unsigned int brut = 0;
	
    for(brut = 0; brut <= 0xffffffff; ++brut){
    		unsigned int temp = rol(brut, original & 0xff);
    		if(target == ror(temp ^ original, (temp>>8) & 0xff)){
        		printf("%x\n", brut);
			}
	}
	
    return 0;
}

得到0xa1beee220xc263a2cb两种可能, 验证后可知是0xc263a2cb, IDA里写解密脚本

from idaapi import *
from idc_bc695 import *

def rol(data, bits):
    for i in range(bits):
        data = ((data<<1)|((data>>31)&1))&((1<<32)-1)
    return data
    
def ror(data, bits):
    for i in range(bits):
        data = ((data>>1)|((data&1)<<31))&((1<<32)-1)
    return data
    
address= 0x401000 
v4 = 0xb7aac296
v3 = 0xc263a2cb

for i in range(0x1000):
    PatchDword(address, Dword(address)^v4)
    v7 = rol(v3, v4&0xff)
    v4 = ror(v7 ^ v4, (v7>>8)&0xff)
    v3 = (v4 + v7)&((1<<32)-1)
    address+=4

print("Done!")

解密后在401000地址处c一下转码, 然后p创建函数入口, 再F5反编译得到真正的password函数

int __stdcall sub_401000(int a1, int a2, int a3, int a4)
{
  int v4; // eax
  char v5; // cl
  char v7[16]; // [esp+0h] [ebp-14Ch]
  char v8[16]; // [esp+10h] [ebp-13Ch]
  char v9[300]; // [esp+20h] [ebp-12Ch] BYREF

  strcpy(v9, "Congratulation!\r\n\r\nPassword is ");
  v7[0] = 86;
  v7[2] = 95;
  v4 = 0;
  v8[0] = 16;
  v8[1] = 32;
  v8[2] = 48;
  v8[3] = 64;
  v8[4] = 80;
  v8[5] = 96;
  v8[6] = 112;
  v8[7] = 0x80;
  v8[8] = -112;
  v8[9] = -96;
  v8[10] = -80;
  v8[11] = -64;
  v8[12] = -48;
  v7[1] = 82;
  v7[3] = 45;
  v7[4] = 15;
  v7[5] = 39;
  v7[6] = 56;
  v7[7] = -52;
  v7[8] = -94;
  v7[9] = -1;
  v7[10] = -111;
  v7[11] = -31;
  v7[12] = -48;
  do
  {
    v5 = v8[v4] ^ v7[v4];
    v7[v4] = v5;
    v9[v4++ + 31] = v5;
  }
  while ( v4 < 13 );
  dword_40509C(0, v9, &unk_4084E0, 64);
  return 0;
}

执行一下即可得到flag

#include <stdio.h>
#include <stdlib.h>
#include <cstring>

int main () {
    int v4;
    char v5;
    char v7[16];
    char v8[16];
    char v9[300];
    strcpy(v9, "Congratulation!\r\n\r\nPassword is ");

    v7[0] = 86;
    v7[2] = 95;
    v4 = 0;
    v8[0] = 16;
    v8[1] = 32;
    v8[2] = 48;
    v8[3] = 64;
    v8[4] = 80;
    v8[5] = 96;
    v8[6] = 112;
    v8[7] = 0x80;
    v8[8] = -112;
    v8[9] = -96;
    v8[10] = -80;
    v8[11] = -64;
    v8[12] = -48;
    v7[1] = 82;
    v7[3] = 45;
    v7[4] = 15;
    v7[5] = 39;
    v7[6] = 56;
    v7[7] = -52;
    v7[8] = -94;
    v7[9] = -1;
    v7[10] = -111;
    v7[11] = -31;
    v7[12] = -48;
    do {
        v5 = v8[v4] ^ v7[v4];
        v7[v4] = v5;
        v9[v4++ + 31] = v5;
    } while ( v4 < 13 );

    printf("%s\n", v9);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值