ASM算法解码

时间:2015-12-27 22:32:03

标签: algorithm assembly 64-bit

我试图理解ASM中的这个问题。这是代码:

MySQLdb.escape_string()

这是编码文本:

45 33 C9                    xor r9d, r9d 
C7 44 24 18 50 72 69 6D     mov [rsp+arg_10], 6D697250h 
66 C7 44 24 1C 65 53        mov [rsp+arg_14], 5365h 
C6 44 24 1E 6F              mov [rsp+arg_16], 6Fh 
4C 63 C1                    movsxd r8, ecx 
85 C9                       test ecx, ecx 
7E 1C                       jle short locret_140001342 
41 8B C9                    mov ecx, r9d 
            loc_140001329: 
48 83 F9 07                 cmp rcx, 7 
49 0F 4D C9                 cmovge rcx, r9 
48 FF C1                    inc rcx 
8A 44 0C 17                 mov al, [rsp+rcx+arg_F] 
30 02                       xor [rdx], al 
48 FF C2                    inc rdx 
49 FF C8                    dec r8 
75 E7                       jnz short loc_140001329 
            locret_140001342: 
C3                          retn  

我已经研究ASM一段时间了,我知道大多数命令,但我还有一些问题,我还没有找到答案。

如何将编码文本插入算法?
什么是arg_10,arg_14等?我假设他们来自编码部分,但我不知道exatcly。

有人可以一行一行地了解这个算法的作用,我理解其中的一些但我需要澄清一下。

我一直在使用visual studio和c ++来测试asm。我知道要运行asm过程,你可以声明一个像这样的函数

07 1D 1E 41 45 2A 00 25 52 0D 04 01 73 06 
24 53 49 39 0D 36 4F 35 1F 08 04 09 73 0E 
34 16 1B 08 16 20 4F 39 01 49 4A 54 3D 1B 
35 00 07 5C 53 0C 08 1E 38 11 2A 30 13 1F 
22 1B 04 08 16 3C 41 33 1D 04 4A  

并像这样使用

extern "C" int function(int a, int b, int c,int d, int f, int g);  

我也知道前四个参数进入int RCX,RDX,R8和R9,其余的都在堆栈上。我对堆栈了解不多,所以我现在不知道如何访问它们。我也知道返回的值是RAX包含的值。所以像这样的东西会增加两个数字:

printf("ASM Returned %d", function(92,2,3,4,5,6));  

正如Jester建议的那样,我将逐行解释我认为代码的作用。

xor eax, eax
mov eax, ecx
add eax, edx
ret  

我仍然不知道arg_xx是什么或编码文本插入此算法的确切程度。

4 个答案:

答案 0 :(得分:2)

这是我对代码的看法。

    ; rdx holds the message location
    ; ecx holds the message length

    xor r9d, r9d                ; r9d = 0
    mov [rsp+arg_10], 6D697250h ; fix up the key
    mov [rsp+arg_14], 5365h 
    mov [rsp+arg_16], 6Fh       ; which is "PrimeSo"
    movsxd r8, ecx              ; length counter
    test ecx, ecx               ; test the  message length
    jle short locret_140001342  ; skip if invalid length
    mov ecx, r9d                ; reset key index to 0
loc_140001329: 
    cmp rcx, 7                  ; check indexing of key
    cmovge rcx, r9              ; reset if o/range
    inc rcx                     ; obfusacte by incrementing first
    mov al, [rsp+rcx+arg_F]     ; ... and indexing wrong offset
    xor [rdx], al               ; encrypt the message byte
    inc rdx                     ; advance message pointer
    dec r8                      ; loop count
    jnz short loc_140001329     ; next message byte
locret_140001342: 
    retn

我用实现算法的C程序解码了消息,但这太容易了,所以我不会发布它。

逆向工程

代码中没有足够的信息来自上而下解决,因为某些寄存器在未加载的情况下使用,并且未定义标签。我通过识别执行加密的指令并从那里开始工作来自下而上解决它。

虽然没有定义堆栈标签,但是命名法足以说明密钥的各个部分实际上是连续的,并且little-endian的假设揭示了密钥。通过查看十六进制字节列表确认了这一点,该列表显示了三个值存储在181C1E的偏移'lsb

答案 1 :(得分:1)

我注意到的一件事是存储在这些堆栈偏移处的值是ASCII:

>>> '5072696d65536f'.decode('hex')
'PrimeSo'

对于输入数据,您可以使用xxd -r -p并从程序中的stdin读取它:xxd -r -p data.hex | ./myprog

必须在源中的某处声明那些arg_14等偏移量。但我猜它们会有十六进制偏移量0xf,0x10,0x14,0x16。

答案 2 :(得分:1)

我认为你的理解基本上是正确的,有一些小的修正:

更正1

test ecx, ecx                 //tests exc and sets the labels

设置标志(而不是标签)。

更正2

cmp rcx, 7                    //moves 7(decimal) into rcx

将rcx与立即值7进行比较,并相应地设置标志。 (即,在此指令之后,如果rcx大于7,则仅执行gt等条件指令。)

更正3

cmovge rcx, r9                //don't know

这种条件(基于您刚刚设置的标志)将r9移动到rcx。条件是ge,所以只有当rcx大于或等于7时才执行该指令.r9包含0,因此这样做的效果是当rcx达到7时将其设置回0。

参数

您没有获得有关函数参数的信息,但似乎可以安全地假设rcx是要解密的数据的原始长度,而rdx是指向数据的指针。

答案 3 :(得分:1)

好的,我已经找到了算法并使其在ASM中也能正常工作。你们是对的,arg_xx是抵消的。 arg_10 == 0x10,arg_f == 0x0f。数据作为具有其长度的数组传入。因此rcx将是这种情况下的数据长度47,而rdx将指向数组的开头。这是我在c ++中用来调用ASM过程的函数。

extern "C" void function(int length, char* message);  

算法非常简单。关键词是" PrimeSo"。它所做的只是对传入的每个值进行XOR运算,其中一个值是" PrimeSo"按顺序递增,一旦达到' o' in" PrimeSo"它可以追溯到P'。因此

cmp rcx, 7       
cmovge rcx, r9   //as Peter de Rivaz stated this will put 0 into rcx if it is greater or equal to seven
inc rcx 

等等

mov al, [rsp + rcx + 0Fh]

将有效地变为[rsp + 1 + 0fh],[rsp + 2 + 0Fh],...,[rsp + 7 + 0Fh]。请注意" PrimeSo"存储在[rsp + 10h]意味着[rsp + 1 + 0Fh]指向' P'。在循环的每次迭代中,al将成为" PrimeSo"中的一个字符。它将循环通过它们。

xor [rdx], al //This will do an xor operation on [rdx](begining of our message) and al wich is 'P' in the first loop.  
              //It will then store the result in it's place.  

inc rdx       //move to next character
dec r8        //decrease counter
jnz short loc_140001329 //and start the loop again  

有了这个说,让我们看看前几个。

xor P, 07 == xor 50, 07 --> 57 = W  
xor r, 1D == xor 72, 1D --> 6F = o  
xor i, 1E == xor 69, 1E --> 77 = w  
xor m, 41 == xor 6D, 41 --> 2C = ,  

对于那些想知道这里是C ++代码:

#include <fstream>

extern "C" void function(int length, char* message);

int main()
{
    char message[] = { 0x07, 0x1D, 0x1E, 0x41, 0x45, 0x2A, 0x00, 0x25, 0x52, 0x0D, 0x04, 0x01, 0x73, 0x06, 0x24, 0x53, 0x49, 0x39, 0x0D, 0x36, 0x4F, 0x35, 0x1F, 0x08, 0x04, 0x09, 0x73, 0x0E, 0x34, 0x16, 0x1B, 0x08, 0x16, 0x20, 0x4F, 0x39, 0x01, 0x49, 0x4A, 0x54, 0x3D, 0x1B, 0x35, 0x00, 0x07, 0x5C, 0x53, 0x0C, 0x08, 0x1E, 0x38, 0x11, 0x2A, 0x30, 0x13, 0x1F, 0x22, 0x1B, 0x04, 0x08, 0x16, 0x3C, 0x41, 0x33, 0x1D, 0x04, 0x4A, '\0'};
    function(sizeof(message) - 1, message);
    printf("Decoded Message is:\n%s\n", message);


    printf("\n");
    system("pause");
    return 0;
}

不,我没有手动将数据插入到消息中。另请注意,我在末尾添加了一个字符串终止符并使用了sizeof(message) - 1来避免解码字符串终止符。
这是ASM代码,这只是一个名为assembly.asm的新文件,其中包含此内容。

.code

function proc
    xor r9d, r9d
    mov dword ptr [rsp + 18h], 6D697250h 
    mov word ptr [rsp + 1Ch], 5365h 
    mov byte ptr [rsp + 1Eh], 6Fh 
    movsxd r8, ecx
    test ecx, ecx
    jle short locret_140001342 
    mov ecx, r9d

loc_140001329:
    cmp rcx, 7
    cmovge rcx, r9
    inc rcx 
    mov al, [rsp + rcx + 17h]
    xor [rdx], al
    inc rdx
    dec r8
    jnz short loc_140001329

locret_140001342:
    ret

function endp
end  

在visual studio中,您可以在此处添加断点并转到debug-&gt; windows-&gt;寄存器和debug-&gt; windows-&gt; memory-memory 1以查看寄存器和程序&#39; s记忆。请注意,rcx将包含计数,rdx将指向编码消息的开头。

谢谢大家的帮助和建议,没有你,我无法做到。