I think you identified the purpose of the functions and its parameters correctly. So, the function
sub_44d84 has four parameters:
(<decryptionFunction=0x1>, <IV>, <bytesToDecrypt>, <decryptedBytes>) and calls the
sub_46d554 function for every blocks using CBC.
sub_46d554 function received 2 parameters:
R0: Encrypted input block
R1: Decrypted output block
The bytes from the input blocks are read out from the first part of the function, performs the decryption steps and writes out to the output buffer in the last part of the function.
To understand the decryption function, first building blocks of the obfuscation should be understand. So, I picked up some example codes after the second bytes was read out from the input block (the start of the function is a little bit messy because of the compiler optimization).
In the above image the line marked with green reads out the second byte of the input block and the orange line initializes the
R2 register. The yellow and blue blocks are perform similar functions. Both blocks starts with an addition, stores the result to a local variable and check whether the result was equal to
0xFF. If the result was
0xFF the value of the
R2 was changed. Since the
R2 was changed only if the addition was
0xFF and the addition used always the
LR (which contained the second byte of the input), the value of the
R2 register can be changed only once. Because the new
R2 value depends only from the
LR these blocks implements a lookup table, which is a substitution box.
[EDIT] The lookup table is built up from the building blocks similar to the highlighted ones. So, in pseudo code, the lookup table is implemented in the following way:
if (input == 0xb1) out = 0x5b
if (input == 0x42) out = 0x56
To understand the reason why the result is stored into a local variable, let's check the next usage of the local variable
It reads out the local variable, which was the result of the addition, and checks whether it is
0xFF similar to the previous cases. Since the value of this local variable will be
0xFF only if the result of the addition was
0xFF in the place, where the value was originally stored, the comparison checks whether the input byte is equal to a specific value again.
If we search for the local variable
var_1A8 in the whole function, we receive a lot of results with a specific patter (
STR means the storage of the addition and the
LDR means the usage of this addition. So, every bytes are checked four times and than another byte will be used.
By comparing all of the input bytes usages with the local variable usages, the following patter can be found:
i0 = input[0x00]
d0_0 = table0[i0]
id = input[0x0d]
d0_d = table1[id]
ia = input[0x0a]
d0_a = table2[ia]
i7 = input[0x07]
d0_7 = table3[i7]
d1_0 = table4[i0]
d1_d = table5[id]
d1_a = table6[ia]
d1_7 = table7[i7]
d2_0 = table8[i0]
d2_d = table9[id]
d2_a = table10[ia]
d2_7 = table11[i7]
d3_0 = table12[i0]
d3_d = table13[id]
d3_a = table14[ia]
d3_7 = table15[i7]
So, reads out 4 bytes, performs the substitution and stores the result in a local variable. After it, the same was performed with the next 4 bytes and so on. After the whole block was processed the stored results were read out and xored value of some previous results was used as a new input, for example:
nb_0 = d0_4 ^ d2_d ^ ...
d0_0 = table16[nb_0]
nb_1 = d1_2 ^ d3_8 ^ ...
d0_1 = table17[nb_1]
d1_0 = table20[nb_0]
d1_d = table21[nb_1]
By checking the pattern of the local variable usage, it clearly seen that it uses 9 round of substitution.
Based on the above, I think, that the decryption function can be an AES-128 implementation. Because the add round key, sub bytes and shift rows steps operations can be implemented with lookup tables in one step, and the mix columns operation in another step. Because there is 9 round only, the initial round and the first round of the AES may be implemented with one lookup table.
So, the key (if it is really an AES implementation, the expanded key) is mixed into the implementation. Although I'm not a crytographer, I guess that you may retrieve the expanded AES key by xoring the values of the lookup tables with the Rijndael S-Box values. However, it seems to be a hard and time-consuming process, so you may consider to emulate the code if you want to just decrypt some data.