BJD hamburger competition
BJDCTF2020]BJD hamburger competition
首先发现是一个由unity引擎编写的游戏
一般遇到由unity编写的程序的逆向题,主要关注的是Assembly-CSarp.dll,其核心代码都在这个 dll 文件中。
这里我们使用ILSpy打开attachment\BJD hamburger competition_Data\Managed\Assembly-CSarp.dll,使用dnspy也行
代码如下
public class ButtonSpawnFruit : MonoBehaviour
{
public GameObject toSpawn;
public int spawnCount = 1;
public AudioSource[] audioSources;
public string result = "";
public static string Md5(string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
byte[] arg_1D_0 = MD5.Create().ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
byte[] array = arg_1D_0;
for (int i = 0; i < array.Length; i++)
{
byte b = array[i];
stringBuilder.Append(b.ToString("X2"));
}
return stringBuilder.ToString().Substring(0, 20);
}
public static string Sha1(string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
byte[] arg_1D_0 = SHA1.Create().ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
byte[] array = arg_1D_0;
for (int i = 0; i < array.Length; i++)
{
byte b = array[i];
stringBuilder.Append(b.ToString("X2"));
}
return stringBuilder.ToString();
}
public void Spawn()
{
FruitSpawner component = GameObject.FindWithTag("GameController").GetComponent<FruitSpawner>();
if (component)
{
if (this.audioSources.Length != 0)
{
this.audioSources[UnityEngine.Random.Range(0, this.audioSources.Length)].Play();
}
component.Spawn(this.toSpawn);
string name = this.toSpawn.name;
if (name == "汉堡底" && Init.spawnCount == 0)
{
Init.secret += 997;
}
else if (name == "鸭屁股")
{
Init.secret -= 127;
}
else if (name == "胡罗贝")
{
Init.secret *= 3;
}
else if (name == "臭豆腐")
{
Init.secret ^= 18;
}
else if (name == "俘虏")
{
Init.secret += 29;
}
else if (name == "白拆")
{
Init.secret -= 47;
}
else if (name == "美汁汁")
{
Init.secret *= 5;
}
else if (name == "柠檬")
{
Init.secret ^= 87;
}
else if (name == "汉堡顶" && Init.spawnCount == 5)
{
Init.secret ^= 127;
string str = Init.secret.ToString();
if (ButtonSpawnFruit.Sha1(str) == "DD01903921EA24941C26A48F2CEC24E0BB0E8CC7")
{
this.result = "BJDCTF{" + ButtonSpawnFruit.Md5(str) + "}";
Debug.Log(this.result);
}
}
Init.spawnCount++;
Debug.Log(Init.secret);
Debug.Log(Init.spawnCount);
}
}
}
可以注意到选取原料构成的str的Sha1需要等于"DD01903921EA24941C26A48F2CEC24E0BB0E8CC7"
DD01903921EA24941C26A48F2CEC24E0BB0E8CC7解密后为1001
然后经过函数Md5
public static string Md5(string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
byte[] arg_1D_0 = MD5.Create().ComputeHash(bytes); //MD5加密
StringBuilder stringBuilder = new StringBuilder();
byte[] array = arg_1D_0;
for (int i = 0; i < array.Length; i++)
{
byte b = array[i];
stringBuilder.Append(b.ToString("X2")); //变大写
}
return stringBuilder.ToString().Substring(0, 20); //取前20
}
可以注意到对MD5后的数值做了变换
最后得到flag
关键知识点
ILSpy
- ILSpy 是一个开源的.Net程序集浏览器和反编译工具,由AlphaSierraPapa 为 SharpDevelop团队构建。
- 下载:https://www.filehorse.com/download-ilspy/
StringBuilder类
append(String str)/append(Char c):字符串连接
toString():返回一个与构建起或缓冲器内容相同的字符串
appendcodePoint(int cp):追加一个代码点,并将其转换为一个或两个代码单元并返回this
setCharAt(int i, char c):将第 i 个代码单元设置为c
insert(int offset, String str)/insert(int offset, Char c):在指定位置之前插入字符(串)
delete(int startIndex,int endIndex):删除起始位置(含)到结尾位置(不含)之间的字符串
[WUSTCTF2020]level3
拿到的是一个未加壳的64位elf文件
使用IDA打开,main反汇编代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
const char *v3; // rax
char v5; // [rsp+Fh] [rbp-41h]
char v6[56]; // [rsp+10h] [rbp-40h] BYREF
unsigned __int64 v7; // [rsp+48h] [rbp-8h]
v7 = __readfsqword(0x28u);
printf("Try my base64 program?.....\n>");
__isoc99_scanf("%20s", v6);
v5 = time(0LL);
srand(v5);
if ( (rand() & 1) != 0 )
{
v3 = (const char *)base64_encode(v6);
puts(v3);
puts("Is there something wrong?");
}
else
{
puts("Sorry I think it's not prepared yet....");
puts("And I get a strange string from my program which is different from the standard base64:");
puts("d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD==");
puts("What's wrong??");
}
return 0;
}
可以看到特殊的字符串d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD==,放入base64解密,发现不行
点入base64_encode函数
char *__fastcall base64_encode(char *a1)
{
int v1; // eax
int v2; // eax
int v4; // [rsp+1Ch] [rbp-54h]
int v5; // [rsp+20h] [rbp-50h]
int v6; // [rsp+24h] [rbp-4Ch]
int v7; // [rsp+28h] [rbp-48h]
int v8; // [rsp+2Ch] [rbp-44h]
char src[56]; // [rsp+30h] [rbp-40h] BYREF
unsigned __int64 v10; // [rsp+68h] [rbp-8h]
v10 = __readfsqword(0x28u);
v1 = strlen(a1);
v8 = v1 % 3;
v7 = v1 / 3;
memset(src, 0, 0x30uLL);
v6 = 0;
v4 = 0;
v5 = 0;
while ( v4 < v7 )
{
src[v6] = base64_table[a1[v5] >> 2];
src[v6 + 1] = base64_table[(16 * (a1[v5] & 3)) | (a1[v5 + 1] >> 4)];
src[v6 + 2] = base64_table[(4 * (a1[v5 + 1] & 0xF)) | (a1[v5 + 2] >> 6)];
v2 = v6 + 3;
v6 += 4;
src[v2] = base64_table[a1[v5 + 2] & 0x3F];
v5 += 3;
++v4;
}
if ( v8 == 1 )
{
src[v6] = base64_table[a1[v5] >> 2];
src[v6 + 1] = base64_table[16 * (a1[v5] & 3)];
strcat(src, "==");
}
else if ( v8 == 2 )
{
src[v6] = base64_table[a1[v5] >> 2];
src[v6 + 1] = base64_table[(16 * (a1[v5] & 3)) | (a1[v5 + 1] >> 4)];
src[v6 + 2] = base64_table[4 * (a1[v5 + 1] & 0xF)];
src[v6 + 3] = 61;
}
strcpy(a1, src);
return a1;
}
点入base64_table
.data:00000000006020A0 base64_table db 'A' ; DATA XREF: base64_encode+B9↑r
.data:00000000006020A0 ; base64_encode+109↑r ...
.data:00000000006020A1 aBcdefghijklmno db 'BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',0
点中base64_table使用ctrl+x,发现引用,点入
__int64 O_OLookAtYou()
{
__int64 result; // rax
char v1; // [rsp+1h] [rbp-5h]
int i; // [rsp+2h] [rbp-4h]
for ( i = 0; i <= 9; ++i )
{
v1 = base64_table[i];
base64_table[i] = base64_table[19 - i];
result = 19 - i;
base64_table[result] = v1;
}
return result;
}
发现对base64表做了变换
在Base64中的可打印字符包括字母A-Z、a-z、数字0-9 ,这样共有62个字符,另外Base64的2个字符是:“+/”
base64加密的具体过程:https://www.cnblogs.com/chengmo/archive/2014/05/18/3735917.html
编写代码:对加密后的字符串进行替换,然后使用base64解密
import base64
crypto='d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=='
list_invert=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')
string1=''
for i in range(10):
temp=list_invert[i]
list_invert[i]=list_invert[19-i]
list_invert[19-i]=temp
string1="".join(list_invert)
print(string1)
table='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
table = str.maketrans(string1, table)
print (base64.b64decode(crypto.translate(table)))
得到结果:
TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
b'wctf2020{Base64_is_the_start_of_reverse}'
最后flag为:
flag


浙公网安备 33010602011771号