我试图理解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是什么或编码文本插入此算法的确切程度。
答案 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的假设揭示了密钥。通过查看十六进制字节列表确认了这一点,该列表显示了三个值存储在18
,1C
和1E
的偏移'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)
我认为你的理解基本上是正确的,有一些小的修正:
test ecx, ecx //tests exc and sets the labels
设置标志(而不是标签)。
cmp rcx, 7 //moves 7(decimal) into rcx
将rcx与立即值7进行比较,并相应地设置标志。 (即,在此指令之后,如果rcx大于7,则仅执行gt等条件指令。)
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将指向编码消息的开头。
谢谢大家的帮助和建议,没有你,我无法做到。