Книга: Practical Malware Analysis: The Hands-On Guide to Dissecting Malicious Software
Назад: Why 64-Bit Malware?
Дальше: Windows 32-Bit on Windows 64-Bit

shows a simple C program that accesses a memory address.

references global data (the variable x). In order to access this data, the instruction encodes the 4 bytes representing the data’s address. This instruction is not position independent, because it will always access address 0x00403374, but if this file were to be loaded at a different location, the instruction would need to be modified so that the mov instruction accessed the correct address, as shown in .

00401004 A1 74 33 40 00 mov     eax, dword_403374

You’ll notice that the bytes of the address are stored with the instruction at , , , and . Remember that the bytes are stored with the least significant byte first. The bytes 74, 33, 40, and 00 correspond to the address 0x00403374.

After recompiling for x64, shows the same mov instruction that appears in .

0000000140001058 8B 05 A2 D3 00 00 mov     eax, dword_14000E400

At the assembly level, there doesn’t appear to be any change. The instruction is still mov eax, dword_address, and IDA Pro automatically calculates the instruction’s address. However, the differences at the opcode level allow this code to be position-independent on x64, but not x86.

In the 64-bit version of the code, the instruction bytes do not contain the fixed address of the data. The address of the data is 14000E400, but the instruction bytes are A2 , D3 , 00 , and 00 , which correspond to the value 0x0000D3A2.

The 64-bit instruction stores the address of the data as an offset from the current instruction pointer, rather than as an absolute address, as stored in the 32-bit version. If this file were loaded at a different location, the instruction would still point to the correct address, unlike in the 32-bit version. In that case, if the file is loaded at a different address, the reference must be changed.

Instruction pointer–relative addressing is a powerful addition to the x64 instruction set that significantly decreases the number of addresses that must be relocated when a DLL is loaded. Instruction pointer–relative addressing also makes it much easier to write shellcode because it eliminates the need to obtain a pointer to EIP in order to access data. Unfortunately, this addition also makes it more difficult to detect shellcode, because it eliminates the need for a call/pop as discussed in . Many of those common shellcode techniques are unnecessary or irrelevant when working with malware written to run on the x64 architecture.

. The first four parameters of the call are passed in the RCX, RDX, R8, and R9 registers; additional ones are stored on the stack.

compares the stack management of 32-bit and 64-bit code. Notice in the graph for a 32-bit function that the stack size grows as arguments are pushed on the stack, and then falls when the stack is cleaned up. Stack space is allocated at the beginning of the function, and moves up and down during the function call. When calling a function, the stack size grows; when the function returns, the stack size returns to normal. In contrast, the graph for a 64-bit function shows that the stack grows at the start of the function and remains at that level until the end of the function.

shows an example of the disassembly for a function call compiled for a 32-bit processor.

sss
sss

© RuTLib.com 2015-2018