ReversingKr-wp(7)

x64 Lotto

在这里插入图片描述

无壳直接分析, 这是一个随机数猜测的程序, 猜对了给flag

__int64 wmain()
{
  unsigned int v0; // eax
  __int64 i; // rbx
  char v2; // r8
  int v3; // edx
  __int64 v4; // rcx
  _BYTE *v5; // rdx
  __int64 v6; // rcx
  char v7; // al
  int v8; // ecx
  __int16 *v9; // rdx
  __int16 v10; // ax
  __int16 v11; // ax
  int v13; // [rsp+40h] [rbp-78h] BYREF
  int v14; // [rsp+44h] [rbp-74h] BYREF
  int v15; // [rsp+48h] [rbp-70h] BYREF
  int v16; // [rsp+4Ch] [rbp-6Ch] BYREF
  int v17; // [rsp+50h] [rbp-68h] BYREF
  int v18; // [rsp+54h] [rbp-64h] BYREF
  int v19[3]; // [rsp+58h] [rbp-60h]
  int v20; // [rsp+64h] [rbp-54h]
  int v21; // [rsp+68h] [rbp-50h]
  int v22; // [rsp+6Ch] [rbp-4Ch]
  __int16 flagstr[25]; // [rsp+70h] [rbp-48h] BYREF
  __int16 v24; // [rsp+A2h] [rbp-16h]

  v13 = 0;
  v14 = 0;
  v15 = 0;
  v16 = 0;
  v17 = 0;
  v18 = 0;
  v19[0] = 0;
  v19[1] = 0;
  v19[2] = 0;
  v20 = 0;
  v21 = 0;
  v22 = 0;
  v0 = time64(0i64);
  srand(v0);
  do
  {
    wprintf(L"\n\t\tL O T T O\t\t\n\n");
    wprintf(L"Input the number: ");
    wscanf_s(L"%d %d %d %d %d %d", &v13, &v14, &v15, &v16, &v17, &v18);
    wsystem(L"cls");
    Sleep(0x1F4u);
    for ( i = 0i64; i < 6; *(&v18 + i) = rand() % 100 )
      ++i;
    v2 = 1;
    v3 = 0;
    v4 = 0i64;
    byte_1400035F0 = 1;
    while ( v19[v4] == *(int *)((char *)&v13 + v4 * 4) )
    {
      ++v4;
      ++v3;
      if ( v4 >= 6 )
        goto LABEL_9;
    }
    v2 = 0;
    byte_1400035F0 = 0;
LABEL_9:
    ;
  }
  while ( v3 != 6 );
  v5 = byte_140003021;
  flagstr[1] = 92;
  flagstr[0] = 184;
  flagstr[2] = 139;
  flagstr[5] = 184;
  flagstr[3] = 107;
  v6 = 0i64;
  flagstr[4] = 66;
  flagstr[6] = 56;
  flagstr[7] = 237;
  flagstr[8] = 219;
  flagstr[9] = 91;
  flagstr[10] = 129;
  flagstr[11] = 41;
  flagstr[12] = 160;
  flagstr[13] = 126;
  flagstr[14] = 80;
  flagstr[15] = 140;
  flagstr[16] = 27;
  flagstr[17] = 134;
  flagstr[18] = 245;
  flagstr[19] = 2;
  flagstr[20] = 85;
  flagstr[21] = 33;
  flagstr[22] = 12;
  flagstr[23] = 14;
  flagstr[24] = 242;
  v24 = 0;
  do
  {
    v7 = byte_140003021[v6 - 1];
    v6 += 5i64;
    *((_WORD *)&v20 + v6 + 1) ^= (unsigned __int8)(v7 - 12);
    *((_WORD *)&v21 + v6) ^= (unsigned __int8)(byte_140003021[v6 - 5] - 12);
    *((_WORD *)&v21 + v6 + 1) ^= (unsigned __int8)(byte_140003021[v6 - 4] - 12);
    *((_WORD *)&v22 + v6) ^= (unsigned __int8)(byte_140003021[v6 - 3] - 12);
    *((_WORD *)&v22 + v6 + 1) ^= (unsigned __int8)(byte_140003021[v6 - 2] - 12);
  }
  while ( v6 < 25 );
  if ( v2 )
  {
    v8 = 0;
    v9 = flagstr;
    do
    {
      v10 = *v9++;
      v11 = v8++ + (v10 ^ 0xF);
      *(v9 - 1) = v11;
    }
    while ( v8 < 25 );
    v24 = 0;
    wprintf(L"%s\n", flagstr);
  }
  wprintf(L"\n", v5);
  return 1i64;
}

发现是内含的flag, 可以动调到flag的wprintf处直接得到flag
在这里插入图片描述

虽然这里只用两个字"动调"就带过去了, 其实省略了1个小时的调试过程描述, 需要从IDA反汇编中定位到3个关键跳转点, nop或者劫持以绕过条件验证, 最后抵达flag输出位置, 文字描述其实意义不大, 就像赵四大佬说的"少动脑多动手"调试起来才能明白.
这三个关键跳转是
在这里插入图片描述

在这里插入图片描述

CSHARP

工具链接: https://github.com/dnSpy/dnSpy/releases
C#, .net逆向, dnSpy打开, 需要动调来破解程序, 先熟悉一下快捷键

单步步入:F11
单步步过:F10
执行至断点:shift+F11
下断点:F9

在这里插入图片描述

发现MetMetMet比较特殊, 进去分析发现是判断的主逻辑

// CSharp.Form1
// Token: 0x06000005 RID: 5 RVA: 0x00002424 File Offset: 0x00000624
private static void MetMetMet(string sss)
{
	byte[] bytes = Encoding.ASCII.GetBytes(Convert.ToBase64String(Encoding.ASCII.GetBytes(sss)));
	AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
	TypeBuilder typeBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave).DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".exe").DefineType("RevKrT1", TypeAttributes.Public);
	MethodBuilder methodBuilder = typeBuilder.DefineMethod("MetMet", MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, null, null);
	TypeBuilder typeBuilder2 = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave).DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".exe").DefineType("RevKrT2", TypeAttributes.Public);
	typeBuilder2.DefineMethod("MetM", MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, null, new Type[]
	{
		typeof(byte[]),
		typeof(byte[])
	}).CreateMethodBody(Form1.bb, Form1.bb.Length);
	Type type = typeBuilder2.CreateType();
	MethodInfo method = type.GetMethod("MetM", BindingFlags.Static | BindingFlags.NonPublic);
	object obj = Activator.CreateInstance(type);
	byte[] array = new byte[]
	{
		1,
		2
	};
	method.Invoke(obj, new object[]
	{
		array,
		bytes
	});
	string str;
	if (array[0] == 1)
	{
		str = "Wrong";
	}
	else
	{
		str = "Correct!!";
	}
	ILGenerator ilgenerator = methodBuilder.GetILGenerator();
	ilgenerator.Emit(OpCodes.Ldstr, str);
	ilgenerator.EmitCall(OpCodes.Call, typeof(MessageBox).GetMethod("Show", new Type[]
	{
		typeof(string)
	}), null);
	ilgenerator.Emit(OpCodes.Pop);
	ilgenerator.Emit(OpCodes.Ret);
	Type type2 = typeBuilder.CreateType();
	MethodInfo method2 = type2.GetMethod("MetMet", BindingFlags.Static | BindingFlags.NonPublic);
	object obj2 = Activator.CreateInstance(type2);
	method2.Invoke(obj2, null);
}

下断点, 运行, 输入后跟踪check函数
在这里插入图片描述

C#的代码风格很繁琐, 懒得看直接无脑步进, 多尝试几次最后可以到达校验函数MetM

using System;

// Token: 0x02000002 RID: 2
public class RevKrT2
{
	// Token: 0x06000001 RID: 1
	private static void MetM(byte[] A_0, byte[] A_1)
	{
		if (A_1.Length == 12)
		{
			A_0[0] = 2;
			if ((A_1[0] ^ 16) != 74)
			{
				A_0[0] = 1;
			}
			if ((A_1[3] ^ 51) != 70)
			{
				A_0[0] = 1;
			}
			if ((A_1[1] ^ 17) != 87)
			{
				A_0[0] = 1;
			}
			if ((A_1[2] ^ 33) != 77)
			{
				A_0[0] = 1;
			}
			if ((A_1[11] ^ 17) != 44)
			{
				A_0[0] = 1;
			}
			if ((A_1[8] ^ 144) != 241)
			{
				A_0[0] = 1;
			}
			if ((A_1[4] ^ 68) != 29)
			{
				A_0[0] = 1;
			}
			if ((A_1[5] ^ 102) != 49)
			{
				A_0[0] = 1;
			}
			if ((A_1[9] ^ 181) != 226)
			{
				A_0[0] = 1;
			}
			if ((A_1[7] ^ 160) != 238)
			{
				A_0[0] = 1;
			}
			if ((A_1[10] ^ 238) != 163)
			{
				A_0[0] = 1;
			}
			if ((A_1[6] ^ 51) != 117)
			{
				A_0[0] = 1;
			}
		}
	}
}

直接写逆

#include <stdlib.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() {
    string res;
    vector<char> arr(12, 0);
    
    arr[0] = 74 ^ 16;
    arr[3] = 70 ^ 51;
    arr[1] = 87 ^ 17;
    arr[2] = 77 ^ 33;
    arr[11] = 44 ^ 17;
    arr[8] = 241 ^ 144;
    arr[4] = 29 ^ 68;
    arr[5] = 49 ^ 102;
    arr[9] = 226 ^ 181;
    arr[7] = 238 ^ 160;
    arr[10] = 163 ^ 238;
    arr[6] = 117 ^ 51;

    res = string(arr.begin(), arr.end());
    cout << res << endl;
}

出来的是base64串, 解码一下就行

Flash Encrypt

.swf文件, 用JPEXS来反编译, 记得 设置→自动反混淆 勾选
在这里插入图片描述
逻辑理清楚了, 根据时间轴查看每个控件的顺序, 依次输入spw即可通过检测
在这里插入图片描述

文件中另存为exe, 运行然后按buttonID4 → 9 → 11 → 7 → 15 → 13顺序输入即可拿到flag (这里运行需要装flash环境, win10可能不会自带, 丢进xp虚拟机里运行
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值