2 #include "reader-dre-st20.h"
10 #define FLASHS 0x7FE00000
11 #define FLASHE 0x7FFFFFFF
12 #define RAMS 0x40000000
13 #define RAME 0x401FFFFF
14 #define IRAMS 0x80000000
15 #define IRAME 0x800017FF
20 // ----------------------------------------------------------------
23 #define STACKMASK (STACKMAX-1)
29 uint32_t flashSize
, ramSize
;
30 int sptr
, stack
[STACKMAX
];
37 static void st20_set_flash(st20_context_t
*ctx
, uint8_t *m
, int len
);
38 static void st20_set_ram(st20_context_t
*ctx
, uint8_t *m
, int len
);
39 static void st20_init(st20_context_t
*ctx
, uint32_t IPtr
, uint32_t WPtr
, int verbose
);
40 static void st20_free(st20_context_t
*ctx
);
42 static void st20_set_call_frame(st20_context_t
*ctx
, uint32_t raddr
, int p1
, int p2
, int p3
);
45 static uint32_t st20_get_reg(st20_context_t
*ctx
, int reg
);
46 static void st20_set_reg(st20_context_t
*ctx
, int reg
, uint32_t val
);
47 static uint8_t st20_rbyte(st20_context_t
*ctx
, uint32_t off
);
48 static void st20_wbyte(st20_context_t
*ctx
, uint32_t off
, uint8_t val
);
49 static uint32_t st20_rword(st20_context_t
*ctx
, uint32_t off
);
50 static void st20_wword(st20_context_t
*ctx
, uint32_t off
, uint32_t val
);
52 #define INVALID_VALUE 0xCCCCCCCC
53 #define ERRORVAL 0xDEADBEEF
55 #define MININT 0x7FFFFFFF
56 #define MOSTPOS 0x7FFFFFFF
57 #define MOSTNEG 0x80000000
60 #define POP() ctx->stack[(ctx->sptr++)&STACKMASK]
61 #define PUSH(v) do { int32_t __v=(v); ctx->stack[(--ctx->sptr)&STACKMASK]=__v; } while(0)
62 #define DROP(n) ctx->sptr+=n
64 #define AAA ctx->stack[ctx->sptr&STACKMASK]
65 #define BBB ctx->stack[(ctx->sptr+1)&STACKMASK]
66 #define CCC ctx->stack[(ctx->sptr+2)&STACKMASK]
68 #define GET_OP() operand|=op1&0x0F
69 #define CLEAR_OP() operand=0
70 #define JUMP(x) ctx->Iptr+=(x)
71 #define POP64() ({ uint32_t __b=POP(); ((uint64_t)POP()<<32)|__b; })
72 #define PUSHPOP(op,val) do { int32_t __a=val; AAA op##= (__a); } while(0)
74 #define RB(off) st20_rbyte(ctx, off)
75 #define RW(off) st20_rword(ctx, off)
76 #define WW(off,val) st20_wword(ctx, off, val)
78 static uint32_t st20_get_reg(st20_context_t
*ctx
, int32_t reg
)
82 case IPTR
: return ctx
->Iptr
;
83 case WPTR
: return ctx
->Wptr
;
84 case AREG
: return AAA
;
85 case BREG
: return BBB
;
86 case CREG
: return CCC
;
91 static void st20_set_reg(st20_context_t
*ctx
, int32_t reg
, uint32_t val
)
95 case IPTR
: ctx
->Iptr
= val
; return;
96 case WPTR
: ctx
->Wptr
= val
; return;
97 case AREG
: AAA
=val
; return;
98 case BREG
: BBB
=val
; return;
99 case CREG
: CCC
=val
; return;
103 static uint8_t *st20_addr(st20_context_t
*ctx
, uint32_t off
)
105 if(off
>= FLASHS
&& off
<= FLASHE
)
107 return &ctx
->flash
[off
- FLASHS
];
109 else if(off
>= RAMS
&& off
<= RAME
)
111 return &ctx
->ram
[off
- RAMS
];
113 else if(off
>= IRAMS
&& off
<= IRAME
)
114 return &ctx
->iram
[off
- IRAMS
];
116 ctx
->invalid
= ERRORVAL
;
117 return (uint8_t *) &ctx
->invalid
;
120 static uint32_t st20_rword(st20_context_t
*ctx
, uint32_t off
)
123 temp
= st20_addr(ctx
, off
);
125 return ((temp
[3]<<24) | (temp
[2]<<16) | (temp
[1]<<8) | temp
[0]);
128 static uint16_t st20_rshort(st20_context_t
*ctx
, uint32_t off
)
131 temp
= st20_addr(ctx
, off
);
133 return ((temp
[0]<<8) | temp
[1]);
136 static uint8_t st20_rbyte(st20_context_t
*ctx
, uint32_t off
)
138 return *st20_addr(ctx
, off
);
141 static void st20_wword(st20_context_t
*ctx
, uint32_t off
, uint32_t val
)
144 temp
= st20_addr(ctx
, off
);
145 temp
[3] = (val
>> 24) & 0xFF;
146 temp
[2] = (val
>> 16) & 0xFF;
147 temp
[1] = (val
>> 8) & 0xFF;
148 temp
[0] = val
& 0xFF;
151 static void st20_wbyte(st20_context_t
*ctx
, uint32_t off
, uint8_t val
)
154 temp
= st20_addr(ctx
, off
);
158 static int32_t st20_decode(st20_context_t
*ctx
, int32_t count
)
162 while(ctx
->Iptr
!= 0)
164 int32_t a
, op1
= RB(ctx
->Iptr
++);
168 case 0x0: // j / jump
173 PUSH(ctx
->Wptr
+ (operand
* 4));
176 case 0x2: // positive prefix
180 AAA
=RW(AAA
+ (operand
* 4));
188 PUSHPOP(+, operand
* 4);
191 case 0x6: // negative prefix
192 operand
= (~operand
) << 4;
195 PUSH(RW(ctx
->Wptr
+ (operand
* 4)));
204 WW(ctx
->Wptr
, ctx
->Iptr
); WW(ctx
->Wptr
+ 4, POP()); WW(ctx
->Wptr
+ 8, POP()); WW(ctx
->Wptr
+ 12, POP());
209 case 0xA: // cj / conditional jump
210 if(AAA
) { DROP(1); } else { JUMP(operand
); }
213 case 0xB: // ajw / adjust workspace
214 ctx
->Wptr
+= operand
* 4;
217 case 0xC: // eqc / equals constant
218 AAA
= (operand
== AAA
? 1 : 0);
222 WW(ctx
->Wptr
+ (operand
* 4), POP());
226 a
= POP(); WW(a
+ (operand
* 4), POP());
229 case 0xF: // opr (secondary ins)
232 case 0x00: a
= AAA
; AAA
= BBB
; BBB
= a
; break;
233 case 0x01: AAA
= RB(AAA
); break;
234 case 0x02: PUSHPOP(+, POP()); break;
235 case 0x04: PUSHPOP(-, POP()); break;
236 case 0x05: PUSHPOP(+, POP()); break;
237 case 0x06: a
= AAA
; AAA
= ctx
->Iptr
; ctx
->Iptr
= a
; break;
238 case 0x08: PUSHPOP(*, POP()); break;
239 case 0x09: a
=POP(); AAA
= (AAA
> a
); break;
240 case 0x0A: a
=POP(); AAA
= a
+ (AAA
* 4); break;
241 case 0x0C: PUSHPOP(-, POP()); break;
242 case 0x1A: { a
= POP(); uint64_t ll
= POP64(); PUSH(ll
% (uint32_t)a
); PUSH(ll
/ (uint32_t)a
); } break;
243 case 0x1B: PUSHPOP(+, ctx
->Iptr
); break;
244 case 0x1D: CCC
= BBB
; BBB
= (AAA
>= 0 ? 0 : -1); break;
245 case 0x1F: PUSHPOP(%, POP()); break;
246 case 0x20: ctx
->Iptr
= RW(ctx
->Wptr
); ctx
->Wptr
= ctx
->Wptr
+ 16; break;
247 case 0x2C: PUSHPOP(/, POP()); break;
249 case 0x32: AAA
=~ AAA
; break;
250 case 0x33: PUSHPOP(^, POP()); break;
251 case 0x34: PUSHPOP(*, 4); break;
252 case 0x35: { a
= POP(); uint64_t ll
= POP64() >> a
; PUSH((ll
>> 32) & 0xFFFFFFFF); PUSH(ll
& 0xFFFFFFFF); } break;
253 case 0x36: { a
= POP(); uint64_t ll
= POP64() << a
; PUSH((ll
>> 32) & 0xFFFFFFFF); PUSH(ll
& 0xFFFFFFFF); } break;
254 case 0x3B: a
= POP(); st20_wbyte(ctx
, a
, POP()); break;
255 case 0x3F: a
= POP(); PUSH(a
& 3); PUSH((uint32_t)a
>> 2); break;
256 case 0x40: a
= POP(); AAA
= (uint32_t)AAA
>> a
; break;
257 case 0x41: a
= POP(); AAA
= (uint32_t)AAA
<< a
; break;
258 case 0x42: PUSH(MOSTNEG
); break;
259 case 0x46: PUSHPOP(&, POP()); break;
260 case 0x4A: { a
= POP(); int32_t b
= POP(); int32_t c
= POP(); while(a
--) st20_wbyte(ctx
, b
++, st20_rbyte(ctx
, c
++)); } break;
261 case 0x4B: PUSHPOP(|, POP()); break;
262 case 0x53: PUSHPOP(*, POP()); break;
263 case 0x5A: PUSH(AAA
); break;
264 case 0x5F: a
= POP(); AAA
= ((uint32_t)AAA
> (uint32_t)a
); break;
265 case 0x78: { a
= POP(); int32_t b
= POP(); int32_t bb
= 0; while(a
--){bb
<<= 1; bb
|= b
& 1; b
>>= 1;} PUSH(bb
);} break;
266 case 0xCA: AAA
= st20_rshort(ctx
, AAA
); break;
268 cs_log("[icg] unknown opcode %X", operand
);
274 if(--count
<= 0 && operand
== 0) return ERR_CNT
;
279 static void st20_set_flash(st20_context_t
*ctx
, uint8_t *m
, int32_t len
)
281 if(ctx
->flash
) free(ctx
->flash
);
282 ctx
->flash
= malloc(len
);
283 if(ctx
->flash
&& m
) memcpy(ctx
->flash
, m
, len
);
284 else memset(ctx
->flash
, 0, len
);
285 ctx
->flashSize
= len
;
288 static void st20_set_ram(st20_context_t
*ctx
, uint8_t *m
, int32_t len
)
290 if(ctx
->ram
) free(ctx
->ram
);
291 ctx
->ram
= malloc(len
);
292 if(ctx
->ram
&& m
) memcpy(ctx
->ram
, m
, len
);
293 else memset(ctx
->ram
, 0, len
);
297 static void st20_init(st20_context_t
*ctx
, uint32_t IPtr
, uint32_t WPtr
, int32_t verbose
)
299 ctx
->Wptr
= WPtr
; ctx
->Iptr
= IPtr
;
300 memset(ctx
->stack
, INVALID_VALUE
, sizeof(ctx
->stack
)); ctx
->sptr
= STACKMAX
- 3;
301 memset(ctx
->iram
, 0, sizeof(ctx
->iram
));
302 ctx
->verbose
= verbose
;
305 static void st20_free(st20_context_t
*ctx
)
307 if(ctx
->flash
) free(ctx
->flash
);
308 if(ctx
->ram
) free(ctx
->ram
);
313 static void st20_set_call_frame(st20_context_t
*ctx
, uint32_t raddr
, int32_t p1
, int32_t p2
, int32_t p3
)
316 st20_wword(ctx
, ctx
->Wptr
, raddr
); // RET
317 st20_wword(ctx
, ctx
->Wptr
+ 4, p1
); //Areg
318 st20_wword(ctx
, ctx
->Wptr
+ 8, p1
); //Breg
319 st20_wword(ctx
, ctx
->Wptr
+ 12, p1
); //Creg
320 st20_wword(ctx
, ctx
->Wptr
+ 16, p2
);
321 st20_wword(ctx
, ctx
->Wptr
+ 20, p3
);
322 st20_set_reg(ctx
, AREG
, raddr
); // RET
325 int st20_run(uint8_t* snip
, uint32_t snip_len
, int addr
, uint8_t *data
, uint16_t overcryptId
)
330 cs_log("[icg] decrypt address = 0x%X, id = %04X", addr
, overcryptId
);
332 cs_log("[icg] CW: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
333 ,data
[0], data
[1], data
[2] , data
[3] , data
[4] , data
[5] , data
[6] , data
[7]
334 ,data
[8], data
[9], data
[10], data
[11], data
[12], data
[13], data
[14], data
[15]);
337 memset(&ctx
, 0, sizeof(st20_context_t
));
338 st20_set_ram(&ctx
, NULL
, 0x1000);
339 st20_set_flash(&ctx
, snip
+ 0x48, (int) (snip_len
- 0x48));
340 st20_init(&ctx
, FLASHS
+ addr
, RAMS
+ 0x100, 1);
341 st20_set_call_frame(&ctx
, 0, RAMS
, RAMS
, RAMS
);
342 for(i
= 0; i
< 8; i
++) st20_wbyte(&ctx
, RAMS
+ i
, data
[i
+n
*8]);
343 if ((error
= st20_decode(&ctx
, 800000)) < 0) break;
344 cs_log("[icg] cw%d ret = %d, AREG = %X", n
+1, error
, st20_get_reg(&ctx
, AREG
));
345 for(i
= 0; i
< 8; i
++) data
[i
+n
*8] = st20_rbyte(&ctx
, RAMS
+ i
);
351 cs_log("[icg] st20 processing failed with error %d", error
);
355 cs_log("[icg] DW: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
356 ,data
[0], data
[1], data
[2] , data
[3] , data
[4] , data
[5] , data
[6] , data
[7]
357 ,data
[8], data
[9], data
[10], data
[11], data
[12], data
[13], data
[14], data
[15]);