Tôi nghĩ câu hỏi của tôi có vẻ hơi lạ, nhưng ở đây nó đi; Tôi đang cố gắng để tạo ra một chương trình tự động trong C + + (chủ yếu là cho niềm vui của nó, nhưng cũng vì một lý do có lập trình) và nó không phải là khó khăn như nó có thể âm thanh. Để thực hiện việc này, bạn phải sử dụng assembly trong thời gian chạy như sau:Một mẫu hợp lệ trong assembly cho đối số variadic
byte * buffer = new byte[5];
*buffer = '0xE9'; // Code for 'jmp'
*(uint*)(buffer + 1) = 'address destination'; // Address to jump to
Điều này dễ hơn rất nhiều, vì tôi chỉ nhắm vào một nền tảng và trình biên dịch; GCC với Linux 32 bit (và cũng chỉ có một quy ước gọi điện, cdecl). Vì vậy, tôi đang cố gắng để tạo ra một chức năng lắp ráp năng động để chuyển hướng cuộc gọi từ gây nên, vì vậy tôi có thể sử dụng phương pháp lớp như callbacks (ngay cả với thư viện API C (với cdecl của khóa học)). Tôi chỉ cần điều này để hỗ trợ con trỏ và các kiểu bản địa (char, int, short etc ...).
ANYTHING MyRedirect(ANY AMOUNT ARGUMENTS)
{
return MyClassFunc('this', ANY AMOUNT ARGUMENTS);
}
Chức năng ở trên, là chức năng tôi muốn tạo trong hội đồng tinh khiết (trong bộ nhớ với C++). Vì hàm này rất đơn giản, ASM của nó cũng đơn giản (tùy thuộc vào các đối số).
55 push %ebp
89 e5 mov %esp,%ebp
83 ec 04 sub $0x4,%esp
8b 45 08 mov 0x8(%ebp),%eax
89 04 24 mov %eax,(%esp)
e8 00 00 00 00 call <address>
c9 leave
c3 ret
Vì vậy, trong chương trình của tôi, tôi đã tạo trình tạo mẫu ASM (vì tôi không biết ASM đặc biệt tốt, tôi tìm kiếm mẫu). Hàm này có thể tạo mã assembly (tính theo byte, cho trường hợp chính xác ở trên, tức là một hàm chuyển hướng và trả về) bằng cách xác định số lượng đối số mà hàm cần. Đây là một đoạn trích từ mã C++ của tôi.
std::vector<byte> detourFunc(10 + stackSize, 0x90); // Base is 10 bytes + argument size
// This becomes 'push %ebp; move %esp, %ebp'
detourFunc.push_back(0x55); // push %ebp
detourFunc.push_back(0x89); // mov
detourFunc.push_back(0xE5); // %esp, %ebp
// Check for arguments
if(stackSize != 0)
{
detourFunc.push_back(0x83); // sub
detourFunc.push_back(0xEC); // %esp
detourFunc.push_back(stackSize); // stack size required
// If there are arguments, we want to push them
// in the opposite direction (cdecl convention)
for(int i = (argumentCount - 1); i >= 0; i--)
{
// This is what I'm trying to implement
// ...
}
// Check if we need to add 'this'
if(m_callbackClassPtr)
{
}
}
// This is our call operator
detourFunc.push_back(0xE8); // call
// All nop, this will be replaced by an address
detourFunc.push_back(0x90); // nop
detourFunc.push_back(0x90); // nop
detourFunc.push_back(0x90); // nop
detourFunc.push_back(0x90); // nop
if(stackSize == 0)
{
// In case of no arguments, just 'pop'
detourFunc.push_back(0x5D); // pop %ebp
}
else
{
// Use 'leave' if we have arguments
detourFunc.push_back(0xC9); // leave
}
// Return function
detourFunc.push_back(0xC3); // ret
Nếu tôi chỉ định không như các stackSize
đây sẽ là kết quả:
55 push %ebp
89 e5 mov %esp,%ebp
e8 90 90 90 90 call <address>
5d pop %ebp
c3 ret
Như bạn có thể thấy, đây là hoàn toàn hợp lệ 32-bit ASM, và sẽ đóng vai trò là 'MyRedirect' nếu nó không có đối số và không cần một con trỏ 'this'. Vấn đề là, tôi muốn thực hiện phần mà nó tạo ra mã ASM, tùy thuộc vào số lượng đối số tôi chỉ định rằng chức năng 'chuyển hướng' sẽ nhận được. Tôi đã thực hiện thành công điều này trong chương trình C++ nhỏ của tôi (đã phá vỡ khuôn mẫu).
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
int val = atoi(argv[1]);
printf("\tpush %%ebp\n");
printf("\tmov %%esp,%%ebp\n");
if(val == 0)
{
printf("\tcall <address>\n");
printf("\tpop %%ebp\n");
}
else
{
printf("\tsub $0x%x,%%esp\n", val * sizeof(int));
for(int i = val; i > 0; i--)
{
printf("\tmov 0x%x(%%ebp),%%eax\n", i * sizeof(int) + sizeof(int));
printf("\tmov %%eax,0x%x(%%esp)\n", i * sizeof(int) - sizeof(int));
}
printf("\tcall <address>\n");
printf("\tleave\n");
}
printf("\tret\n");
return 0;
}
Chức năng này in chính xác cùng mẫu với mã ASM được tạo bởi 'objdump'. Vì vậy, câu hỏi của tôi là; điều này có hợp lệ trong mọi trường hợp nếu tôi chỉ chỉ muốn có chức năng chuyển hướng như chức năng ở trên, bất kể đối số, nếu nó chỉ nằm dưới Linux 32bit, hoặc có bất kỳ cạm bẫy nào tôi cần biết không? Ví dụ; ASM được tạo ra có khác biệt với 'quần short' hoặc 'ký tự' hay công việc này (tôi chỉ thử nghiệm với số nguyên), và nếu tôi gọi hàm trả về 'void' (điều đó ảnh hưởng đến ASM) thì sao?
tôi có thể giải thích tất cả mọi thứ một chút mờ, vì vậy hãy hỏi thay vì bất kỳ sự hiểu lầm :)
LƯU Ý: Tôi không muốn biết lựa chọn thay thế, tôi thưởng thức thực hiện hiện tại của tôi và nghĩ rằng đó là một cái rất thú vị, tôi sẽ đánh giá cao sự giúp đỡ của bạn về chủ đề này.
EDIT: Trong trường hợp quan tâm, đây là một số bãi cho C++ trên mã: link
Một sự thay thế rất tốt để mã hóa hướng dẫn bằng tay là thư viện [asmjit] (http://code.google.com/p/asmjit/) (trái với tên, đây không phải là trình biên dịch JIT, chỉ là một cái gì đó Trình biên dịch JIT có thể sử dụng). –
@afishwhoswimsaround Thư viện đó trông thật tuyệt vời. Theo nghĩa đen. Điều đó có vẻ là _exactly_ những gì tôi cần. Câu hỏi nhanh; Tôi có thể tạo ra một chức năng tự động với thư viện này (với malloc hoặc một cái gì đó) vì vậy tôi có thể 'chuyển hướng' (với lắp ráp 'jmp') các chức năng khác ('móc' chúng) cho các chức năng được tạo ra? –
Có, hãy xem các ví dụ http://code.google.com/p/asmjit/wiki/Examples –