使用mruby生成字节码
./mruby -v babycode.mrb
mruby 3.1.0 (2022-05-12)
irep 0x55a0b4a19dc0 nregs=5 nlocals=2 pools=1 syms=5 reps=2 ilen=55
local variable names:
R1:p
000 LOADNIL R2
002 LOADNIL R3
004 CLASS R2 :Crypt
007 EXEC R2 I(0:0x55a0b4a19e70)
010 TCLASS R2
012 METHOD R3 I(1:0x55a0b4a1a670)
015 DEF R2 :check
018 SSEND R2 :gets n=0
022 SEND R2 :chomp n=0
026 MOVE R1 R2 ; R1:p
029 MOVE R3 R1 ; R1:p
032 SSEND R2 :check n=1
036 JMPNOT R2 050
040 STRING R3 L(0) ; yes
043 SSEND R2 :puts n=1
047 JMP 052
050 LOADNIL R2
052 RETURN R2
054 STOP
//Crypt 的构造函数???
irep 0x55a0b4a19e70 nregs=3 nlocals=1 pools=0 syms=1 reps=1 ilen=12
000 LOADNIL R1
002 LOADNIL R2
004 CLASS R1 :CIPHER
007 EXEC R1 I(0:0x55a0b4a19f40)
010 RETURN R1
//
irep 0x55a0b4a19f40 nregs=3 nlocals=1 pools=0 syms=6 reps=4 ilen=55
000 LOADI32 R1 305419896
006 SETCONST XX R1
009 LOADI R1 16
012 SETCONST YY R1
015 LOADSELF R1
017 SCLASS R1
019 METHOD R2 I(0:0x55a0b4a1a080)
022 DEF R1 :encrypt
//这些是私有的🐎????
025 TCLASS R1
027 METHOD R2 I(1:0x55a0b4a1a120)
030 DEF R1 :encrypt
033 SSEND R1 :private n=0
037 TCLASS R1
039 METHOD R2 I(2:0x55a0b4a1a440)
042 DEF R1 :to_key
045 TCLASS R1
047 METHOD R2 I(3:0x55a0b4a1a510)
050 DEF R1 :enc_one
053 RETURN R1
//encrypt 函数
irep 0x55a0b4a1a080 nregs=9 nlocals=5 pools=0 syms=3 reps=0 ilen=29
local variable names:
R1:t
R2:p
R3:&
R4:cip
000 ENTER 2:0:0:0:0:0:0 (0x80000)
004 GETCONST R5 CIPHER
007 SEND R5 :new n=0
011 MOVE R4 R5 ; R4:cip
014 MOVE R5 R4 ; R4:cip
017 MOVE R6 R1 ; R1:t
020 MOVE R7 R2 ; R2:p
023 SEND R5 :encrypt n=2
027 RETURN R5
//encrypt 函数
irep 0x55a0b4a1a120 nregs=16 nlocals=11 pools=1 syms=8 reps=1 ilen=346
local variable names:
R1:t
R2:p
R3:&
R4:key
R5:c
R6:n
R7:num1
R8:num2
R9:enum1
R10:enum2
000 ENTER 2:0:0:0:0:0:0 (0x80000)
//
004 MOVE R12 R2 ; R2:p
007 SSEND R11 :to_key n=1
011 MOVE R4 R11 ; R4:key
014 ARRAY R5 R5 0 ; R5:c
017 LOADI_0 R6 ; R6:n
019 MOVE R11 R6 ; R6:n
022 MOVE R12 R1 ; R1:t
025 SEND R12 :length n=0
029 LT R11 R12
031 JMPNOT R11 327
//loop
035 MOVE R11 R1 ; R1:t
038 MOVE R12 R6 ; R6:n
041 GETIDX R11 R12
043 SEND R11 :ord n=0
047 SEND R11 :to_i n=0
051 LOADI R12 24
054 SEND R11 :<< n=1
058 MOVE R7 R11 ; R7:num1
061 MOVE R11 R7 ; R7:num1
//
064 MOVE R12 R1 ; R1:t
067 MOVE R13 R6 ; R6:n
070 ADDI R13 1
073 GETIDX R12 R13
075 SEND R12 :ord n=0
079 SEND R12 :to_i n=0
083 LOADI R13 16
086 SEND R12 :<< n=1
090 ADD R11 R12
092 MOVE R7 R11 ; R7:num1
095 MOVE R11 R7 ; R7:num1
//
098 MOVE R12 R1 ; R1:t
101 MOVE R13 R6 ; R6:n
104 ADDI R13 2
107 GETIDX R12 R13
109 SEND R12 :ord n=0
113 SEND R12 :to_i n=0
117 LOADI R13 8
120 SEND R12 :<< n=1
124 ADD R11 R12
126 MOVE R7 R11 ; R7:num1
129 MOVE R11 R7 ; R7:num1
//
132 MOVE R12 R1 ; R1:t
135 MOVE R13 R6 ; R6:n
138 ADDI R13 3
141 GETIDX R12 R13
143 SEND R12 :ord n=0
147 SEND R12 :to_i n=0
151 ADD R11 R12
153 MOVE R7 R11 ; R7:num1
//
156 MOVE R11 R1 ; R1:t
159 MOVE R12 R6 ; R6:n
162 ADDI R12 4
165 GETIDX R11 R12
167 SEND R11 :ord n=0
171 SEND R11 :to_i n=0
175 LOADI R12 24
178 SEND R11 :<< n=1
182 MOVE R8 R11 ; R8:num2
185 MOVE R11 R8 ; R8:num2
188 MOVE R12 R1 ; R1:t
191 MOVE R13 R6 ; R6:n
194 ADDI R13 5
197 GETIDX R12 R13
199 SEND R12 :ord n=0
203 SEND R12 :to_i n=0
207 LOADI R13 16
210 SEND R12 :<< n=1
214 ADD R11 R12
216 MOVE R8 R11 ; R8:num2
219 MOVE R11 R8 ; R8:num2
222 MOVE R12 R1 ; R1:t
225 MOVE R13 R6 ; R6:n
228 ADDI R13 6
231 GETIDX R12 R13
233 SEND R12 :ord n=0
237 SEND R12 :to_i n=0
241 LOADI R13 8
244 SEND R12 :<< n=1
248 ADD R11 R12
250 MOVE R8 R11 ; R8:num2
253 MOVE R11 R8 ; R8:num2
//
256 MOVE R12 R1 ; R1:t
259 MOVE R13 R6 ; R6:n
262 ADDI R13 7
265 GETIDX R12 R13
267 SEND R12 :ord n=0
271 SEND R12 :to_i n=0
275 ADD R11 R12
277 MOVE R8 R11 ; R8:num2
//
//enc_one(num1,num2,key)
280 MOVE R12 R7 ; R7:num1
283 MOVE R13 R8 ; R8:num2
286 MOVE R14 R4 ; R4:key
289 SSEND R11 :enc_one n=3
// 结果附加到数组末尾。
//arr = arr << num1
//arr = arr << num2
293 AREF R9 R11 0 ; R9:enum1
297 AREF R10 R11 1 ; R10:enum2
301 MOVE R11 R5 ; R5:c
304 MOVE R12 R9 ; R9:enum1
307 SEND R11 :<< n=1
311 MOVE R11 R5 ; R5:c
314 MOVE R12 R10 ; R10:enum2
317 SEND R11 :<< n=1
//
321 ADDI R6 8 ; R6:n
324 JMP 019
//生成字符串, enc_str = arr.collect{|x| sprintf("%.8x",x)}.join("")
327 MOVE R11 R5 ; R5:c
330 BLOCK R12 I(0:0x55a0b4a1a370)
333 SENDB R11 :collect n=0
337 STRING R12 L(0) ;
340 SEND R11 :join n=1
344 RETURN R11
irep 0x55a0b4a1a370 nregs=7 nlocals=3 pools=1 syms=1 reps=0 ilen=16
local variable names:
R1:x
R2:&
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 STRING R4 L(0) ; %.8x
007 MOVE R5 R1 ; R1:x
010 SSEND R3 :sprintf n=2
014 RETURN R3
//to key......
//"aaaassssddddffff" ----> [1633771873, 1936946035, 1684300900, 1717986918]
irep 0x55a0b4a1a440 nregs=6 nlocals=3 pools=1 syms=1 reps=0 ilen=16
local variable names:
R1:p
R2:&
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 MOVE R3 R1 ; R1:p
007 STRING R4 L(0) ; L*
010 SEND R3 :unpack n=1
014 RETURN R3
//
irep 0x55a0b4a1a510 nregs=11 nlocals=8 pools=0 syms=2 reps=1 ilen=42
local variable names:
R1:num1
R2:num2
R3:key
R4:&
R5:y
R6:z
R7:s
000 ENTER 3:0:0:0:0:0:0 (0xc0000)
004 MOVE R8 R1 ; R1:num1
007 MOVE R9 R2 ; R2:num2
010 LOADI_0 R10
/*
y = num1
z = num2
r3 = key
s = delta.
*/
012 MOVE R5 R8 ; R5:y
015 MOVE R6 R9 ; R6:z
018 MOVE R7 R10 ; R7:s
/*
16.times do
tea_encrypt_xxx()
end
*/
021 GETCONST R8 YY
024 BLOCK R9 I(0:0x55a0b4a1a5e0)
027 SENDB R8 :times n=0
031 MOVE R8 R5 ; R5:y
034 MOVE R9 R6 ; R6:z
037 ARRAY R8 R8 2
// return {y,z};
040 RETURN R8
irep 0x55a0b4a1a5e0 nregs=10 nlocals=3 pools=1 syms=5 reps=0 ilen=186
local variable names:
R1:i
R2:&
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 GETUPVAR R3 5 0
008 GETUPVAR R4 6 0
012 LOADI_3 R5
014 SEND R4 :<< n=1
018 GETUPVAR R5 6 0
022 LOADI_5 R6
024 SEND R5 :>> n=1
028 SEND R4 :^ n=1
032 GETUPVAR R5 6 0
036 ADD R4 R5
///
038 GETUPVAR R5 7 0
042 GETUPVAR R6 3 0
046 GETUPVAR R7 7 0
050 LOADI R8 11
053 SEND R7 :>> n=1
057 ADDI R7 1
060 LOADI_3 R8
062 SEND R7 :& n=1
066 GETIDX R6 R7
068 ADD R5 R6
070 SEND R4 :^ n=1
074 ADD R3 R4
076 SETUPVAR R3 5 0
//
080 LOADL R4 L(0) ; 4294967295
083 SEND R3 :& n=1
087 SETUPVAR R3 5 0
//
//delta += XX
091 GETUPVAR R3 7 0
095 GETCONST R4 XX
098 ADD R3 R4
100 SETUPVAR R3 7 0
//
104 GETUPVAR R3 6 0
108 GETUPVAR R4 5 0
112 LOADI_3 R5
114 SEND R4 :<< n=1
118 GETUPVAR R5 5 0
122 LOADI_5 R6
124 SEND R5 :>> n=1
128 SEND R4 :^ n=1
132 GETUPVAR R5 5 0
136 ADD R4 R5
138 GETUPVAR R5 7 0
142 GETUPVAR R6 3 0
146 GETUPVAR R7 7 0
150 ADDI R7 1
153 LOADI_3 R8
155 SEND R7 :& n=1
159 GETIDX R6 R7
161 ADD R5 R6
163 SEND R4 :^ n=1
167 ADD R3 R4
169 SETUPVAR R3 6 0
173 LOADL R4 L(0) ; 4294967295
176 SEND R3 :& n=1
180 SETUPVAR R3 6 0
184 RETURN R3
//check 函数
//check(flag)
irep 0x55a0b4a1a670 nregs=13 nlocals=8 pools=2 syms=7 reps=0 ilen=128
local variable names:
R1:p
R2:&
R3:i
R4:lst_ch
R5:c
R6:k
R7:cipher_text
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 LOADI_0 R3 ; R3:i
006 LOADI_0 R4 ; R4:lst_ch
008 MOVE R8 R3 ; R3:i
011 MOVE R9 R1 ; R1:p ,
014 SEND R9 :length n=0
018 LT R8 R9
020 JMPNOT R8 086
//body
024 MOVE R8 R1 ; R1:p
027 MOVE R9 R3 ; R3:i
030 GETIDX R8 R9
032 SEND R8 :ord n=0
//temp = data[i]
036 MOVE R5 R8 ; R5:c
039 MOVE R8 R5 ; R5:c
042 MOVE R9 R4 ; R4:lst_ch
045 SEND R8 :^ n=1
049 MOVE R9 R3 ; R3:i
052 ADDI R9 1
055 SEND R8 :^ n=1
059 SEND R8 :chr n=0
//data[i] = (data[i] ^ last_ch) ^ (i + 1)
063 MOVE R9 R1 ; R1:p
066 MOVE R10 R3 ; R3:i
069 MOVE R11 R8
072 SETIDX R9 R10 R11
//last_ch = temp
074 MOVE R8 R5 ; R5:c
077 MOVE R4 R8 ; R4:lst_ch
080 ADDI R3 1 ; R3:i
083 JMP 008
//
086 STRING R6 L(0) ; aaaassssddddffff ; R6:k
089 GETCONST R8 Crypt
092 GETMCNST R8 R8::CIPHER
095 MOVE R9 R1 ; R1:p
098 MOVE R10 R6 ; R6:k
/*
encrypt(self,data,key)
*/
101 SEND R8 :encrypt n=2
105 MOVE R7 R8 ; R7:cipher_text
108 MOVE R8 R7 ; R7:cipher_text
111 STRING R9 L(1) ; f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb
114 EQ R8 R9
116 JMPNOT R8 124
120 LOADT R8
122 RETURN R8
124 LOADF R8
126 RETURN R8
里面的字节码自行google
正向和逆向的c代码:
#include <stdio.h>
#include <string.h>
#include <string>
using namespace std;
unsigned char szKey[] = "aaaassssddddffff";
char g_szFlag[256] = { 0 };
unsigned int XX = 305419896;
unsigned int YY = 16;
unsigned int enc_data[10] = { 0 };
void dec_one(unsigned int&num1, unsigned int&num2, unsigned int *key){
unsigned long long delta = 0;
unsigned int t = 0;
for (int j = 0; j < 16; j++){
delta += XX;
}
//
for (int j = 0; j < 16; j++){
t = (((num1 << 3) ^ (num1 >> 5)) + num1) ^ (delta + key[(delta + 1) & 3]);
num2 -= t;
delta -= XX;
//
t = (((num2 << 3) ^ (num2 >> 5)) + num2) ^ (delta + key[((delta >> 11) + 1) & 3]);
num1 -= t;
}
}
void enc_one(unsigned int&num1,unsigned int&num2,unsigned int*key){
unsigned long long delta = 0;
for (int i = 0; i < 1; i++){
unsigned int t1 = 0;
unsigned int t2 = 0;
t1 = (((num2 << 3) ^ (num2 >> 5)) + num2) ^ (delta + key[((delta >> 11) + 1) & 3]);
num1 += t1;
delta += XX;
t2 = (((num1 << 3) ^ ( num1 >> 5)) + num1) ^ (delta + key[(delta + 1) & 3]);
num2 += t2;
}
}
void encrypt(unsigned char*data,int len,unsigned int* key){
for (int i = 0,j = 0; i < len; i += 8,j++){
//改变字节序
unsigned int t = 0;
unsigned int num1, num2;
t = *(unsigned int*)&data[i];
num1 =(((t & 0xff) << 24) | ((t & 0xff00) << 8) | ((t & 0xff0000) >> 8) | ((t & 0xff000000) >> 24));
//num1 = t;
t = *(unsigned int*)&data[i + 4];
num2 = (((t & 0xff) << 24) | ((t & 0xff00) << 8) | ((t & 0xff0000) >> 8) | ((t & 0xff000000) >> 24));
//num2 = t;
enc_one(num1, num2, key);
//
enc_data[j * 2 + 0] = num1;
enc_data[j * 2 + 1] = num2;
}
}
void check(char*flag){
int len = strlen(flag);
unsigned char last_ch = 0;
for (int i = 0; i < len; i++){
unsigned char t = flag[i];
unsigned char r8 = flag[i];
r8 = (r8 ^ last_ch) ^ (i + 1);
flag[i] = r8;
last_ch = t;
}
encrypt((unsigned char*)flag, len,(unsigned int*)szKey);
if (!strcmp(g_szFlag, "f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb")){
printf("OK!");
return;
}
}
char enc[] = "f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb";
void decode(unsigned int *key){
//
unsigned int arr[11] = { 0 };
unsigned char*p = NULL;
/*for (int i = 0; i < 10; i++){
arr[i] = enc_data[i];
}*/
for (int i = 0; i < 10; i ++)
{
char buff[12] = { 0 };
unsigned int val = 0;
memcpy(buff, enc + i*8, 8);
sscanf(buff, "%x", &val);
arr[i] = val;
}
for (int i = 0; i < 5; i++){
unsigned int num1 = arr[i * 2 + 0];
unsigned int num2 = arr[i * 2 + 1];
unsigned int t = 0;
dec_one(num1, num2, (unsigned int*)szKey);
//交换字节序
t = num1;
num1 = (((t & 0xff) << 24) | ((t & 0xff00) << 8) | ((t & 0xff0000) >> 8) | ((t & 0xff000000) >> 24));
t = num2;
num2 = (((t & 0xff) << 24) | ((t & 0xff00) << 8) | ((t & 0xff0000) >> 8) | ((t & 0xff000000) >> 24));
//
arr[i * 2 + 0] = num1;
arr[i * 2 + 1] = num2;
}
//tea decrypt
//
p = (unsigned char*)arr;
unsigned char last_ch = 0;
for (int i = 0; i < 40; i++){
p[i] = (p[i] ^ last_ch) ^ (i + 1);
last_ch = p[i];
}
//
puts((char*)p);
}
int main()
{
decode((unsigned int*)szKey);
return 0;
}
一些需要注意的地方:
Ruby 的<<作用于数组是append到数组末尾
enc_one进行了 YY (16次) 类似tea 的加密操作,每次enc_one之后将两个数字添加到结果数组
将enc最后的到的数组 对每一个元素 进行 sprintf 生成16进制字符串,最后把这些字符串拼接起来
to_key 和 C语言里面(unsigned int*)szKey 一样
enc_one里面 (num<<3) ^ (num>>5) 中间是异或,由于是int32(不是uint8),不能换成 or