cff blocks is equal to number of sparse-switch-payload count
- first bytecode of function is initialization for cff which sets str
1a00(switch reg) ????(strId) -> const string v0, "xxxx"string@strId
- each block dispatcher startswith
6e10 ????(methodId) 0000(switch reg) -> invoke-virtual {v0}, Ljava/lang/String;->hashCode()I # method@d71d
v0 holds object to be hashCode'd.
- block dispatcher ends with
sparse-switch
instruction:
2c 01(reg that holds calculated value) 1600 0000(offset to sparse-switch-payload) -> sparse-switch v1, :s_switch_t
0x8ca750+(0x16*2) = 0x8ca77c payload table
- hashCode object is always stored at register switch reg. Therefore each block ends with:
1a00(switch reg) ???? -> const v0, "xxxx"`
28?? -> goto :current_block_dispatcher
example cff'ed function:
Class: Lcom/plus/currencyconverter/virtual/model/VirtualRatesModel;
.method public b(Lretrofit2/d;Ljava/lang/Throwable;)V
.registers 7
.param p1, "":Lretrofit2/d;
.param p2, "":Ljava/lang/Throwable;
008ca72c: 1a00 9db7 0000: const-string v0, "ۜۗۛۘۡۨۘۙۜۧۘۜۙ۠ۛۧۢۥۢۚ۬۬ۥۘۦۥۦۘ۫۠ۤۤۧۡۘ۟۫ۦۘۗۙۖۘ۟ۗ۠ۜۨۢۢ۫ۢۚۡۚ" # string@b79d
goto_0002: # 5 refs
008ca730: 6e10 1dd7 0000 0002: invoke-virtual {v0}, Ljava/lang/String;->hashCode()I # method@d71d
008ca736: 0a01 0005: move-result v1
008ca738: 1302 c001 0006: const/16 v2, 0x1c0
008ca73c: b721 0008: xor-int/2addr v1, v2
008ca73e: d711 b302 0009: xor-int/lit16 v1, v1, 0x2b3
008ca742: 1302 c100 000b: const/16 v2, 0xc1
008ca746: 1403 3623 0e8d 000d: const v3, -1928453322
008ca74c: b721 0010: xor-int/2addr v1, v2
008ca74e: b731 0011: xor-int/2addr v1, v3
008ca750: 2c01 1600 0000 0012: sparse-switch v1, :s_switch_0028
008ca756: 28ed 0015: goto :goto_0002
s_case_0016: # case 1952522358
008ca758: 1a00 6ebd 0016: const-string v0, "۟ۥۦۘ۠ۧۨۘۡۤ۟ۗۧۥۘۛۨۖۘۤۢۜۦۗ۬ۧۦ۬ۚ۟ۤۤۜۨۚۛۖۧۧۡۘۡۡۚ۠ۦۚۡ۬ۚ۟ۖۙ" # string@bd6e
008ca75c: 28ea 0018: goto :goto_0002
s_case_0019: # case 680223507
008ca75e: 1a00 3ba3 0019: const-string v0, "ۖ۟ۡ۬ۛۗۦۥۨۘۛۧۘۘۚۤۥ۟۠ۚۢ۟ۧۦۦۡۘ۟ۛ۬۠ۤۤ" # string@a33b
008ca762: 28e7 001b: goto :goto_0002
s_case_001c: # case -1353228980
008ca764: 1a00 7ad4 001c: const-string v0, "ۧۗۤۨۡۢ۫۠ۘ۫ۙۡۘۛۨ۬ۛ۟ۡۘۥۦۨۘ۫ۨۡۘۡۚ۠ۥ۬" # string@d47a
008ca768: 28e4 001e: goto :goto_0002
s_case_001f: # case 1753120390
008ca76a: 5440 1866 001f: iget-object v0, p0, Lcom/plus/currencyconverter/virtual/model/VirtualRatesModel$a;->a:Lcom/plus/currencyconverter/d/b$a; # field@6618
008ca76e: 7210 87c8 0000 0021: invoke-interface {v0}, Lcom/plus/currencyconverter/d/b$a;->b()V # method@c887
008ca774: 1a00 25cf 0024: const-string v0, "ۥۢ۫ۜ۬۫۬ۤۢۡۛۜۘۘۡۜۦۨۘۧۤۖۥۡۜۗۥۢۚۤ۟ۨۦۘ۟ۜۢۦۦ۫۬۫۟ۚ۫ۙ۟ۢۙۤۤۜۥۥ" # string@cf25
008ca778: 28dc 0026: goto :goto_0002
s_case_0027: # case -818024012
008ca77a: 0e00 0027: return-void
s_switch_0028:
008ca77c: 0002 0500 4c5d 57af ... 0028: sparse-switch-payload
case -1353228980: -> :s_case_001c
case -818024012: -> :s_case_0027
case 680223507: -> :s_case_0019
case 1753120390: -> :s_case_001f
case 1952522358: -> :s_case_0016
.end payload
- Identify init, dispatcher and blocks.
- Extract switch function (dispatcher)
- Start from init, store each sparse-switch-payload
- remove reduntant codes (const string and goto) and add block codes to each other