Tôi muốn tìm địa chỉ thực của một biến được xác định trong quy trình không gian người dùng? Có cách nào để làm điều đó bằng cách sử dụng đặc quyền root?Làm thế nào để tìm địa chỉ vật lý của một biến từ không gian người dùng trong Linux?
Trả lời
Trước tiên, tại sao bạn muốn thực hiện việc này? Mục đích của các hệ thống VM hiện đại là loại bỏ trình lập trình ứng dụng khỏi sự phức tạp của bố cục bộ nhớ vật lý. Gving chúng mỗi không gian địa chỉ đồng phục của riêng mình để làm cho cuộc sống của họ dễ dàng hơn.
Nếu bạn muốn thực hiện việc này, bạn gần như chắc chắn sẽ cần sử dụng mô-đun hạt nhân. Nhận địa chỉ ảo của biến theo cách thông thường, sử dụng địa chỉ này để lập chỉ mục vào các bảng trang quy trình và đọc giá trị bạn tìm thấy (địa chỉ vật lý của khung). Sau đó, thêm trang bù đắp để có được địa chỉ vật lý hoàn chỉnh. Lưu ý rằng bạn sẽ không thể sử dụng địa chỉ này khi bật phân trang.
(Nếu may mắn bạn có thể để có được địa chỉ của khung của một vùng VM từ hệ thống tập tin/proc và do đó wouldnt yêu cầu viết một mô-đun hạt nhân của mình.)
... và trừ khi bạn khóa trang vào bộ nhớ, địa chỉ vật lý đó có thể thay đổi bất cứ lúc nào. – caf
Bạn không cần viết mô-đun hạt nhân: như các ví dụ khác giải thích, điều này đã được hiển thị thông qua '/ proc/$ pid/sơ đồ trang '. – poolie
Có thể thú vị trong các kiến trúc NUMA để biết địa chỉ vật lý của các biến số – horro
(chỉnh sửa: Nếu theo "địa chỉ vật lý ", bạn có nghĩa là cấp độ" trong đó RAM là các bit của tôi được lưu trữ ", sau đó câu trả lời sau là không phù hợp.)
Bạn không cần quyền root để thực hiện việc này. Những gì bạn cần thay vào đó là một trình gỡ lỗi. Và ở đây chúng tôi đi (sử dụng hệ thống Linux trên x86_64):
Trước tiên, chúng tôi cần một chương trình nhỏ để chơi cùng. Điều này truy cập một biến toàn cầu và in nó hai lần liên tiếp. Nó có hai biến toàn cầu, mà chúng ta tìm thấy trong bộ nhớ sau này.
#include <stdio.h> int a, b = 0; int main(void) { printf("a: "); if (fscanf("%d", &a) < 1) return 0; printf("a = %d\n", myglobal); printf("b: "); if (fscanf("%d", &b) < 1) return 0; printf("a = %d, b = %d\n", a, b); return 0; }
Bước 1: Biên dịch chương trình và xóa tất cả thông tin gỡ lỗi khỏi chương trình, vì vậy chúng tôi không nhận được bất kỳ gợi ý nào từ trình gỡ lỗi mà chúng tôi không gặp phải trong thực tế.
$ gcc -s -W -Wall -Os -o ab ab.c
Bước 2: Chạy chương trình và nhập một trong hai số.
$ ./ab a: 123 a = 123 b: _
Bước 3: Tìm quy trình.
$ ps aux | grep ab roland 21601 0.0 0.0 3648 456 pts/11 S+ 15:17 0:00 ./ab roland 21665 0.0 0.0 5132 672 pts/12 S+ 15:18 0:00 grep ab
Bước 4: Đính kèm trình gỡ lỗi cho quy trình (21601).
$ gdb ... (gdb) attach 21601 ... (gdb) where #0 0x00007fdecfdd2970 in read() from /lib/libc.so.6 #1 0x00007fdecfd80b40 in _IO_file_underflow() from /lib/libc.so.6 #2 0x00007fdecfd8230e in _IO_default_uflow() from /lib/libc.so.6 #3 0x00007fdecfd66903 in _IO_vfscanf() from /lib/libc.so.6 #4 0x00007fdecfd7245c in scanf() from /lib/libc.so.6 #5 0x0000000000400570 in ??() #6 0x00007fdecfd2f1a6 in __libc_start_main() from /lib/libc.so.6 #7 0x0000000000400459 in ??() #8 0x00007fffd827da48 in ??() #9 0x000000000000001c in ??() #10 0x0000000000000001 in ??() #11 0x00007fffd827f9a2 in ??() #12 0x0000000000000000 in ??()
Khung thú vị là số 5, vì nó là giữa một số mã gọi main
chức năng và scanf
chức năng, vì vậy nó phải là chức năng main
của chúng tôi. Tiếp tục phiên gỡ lỗi:
(gdb) frame 5 ... (gdb) disassemble $pc $pc+50 ... 0x0000000000400570 : test %eax,%eax 0x0000000000400572 : jle 0x40058c <[email protected]+372> 0x0000000000400574 : mov 0x2003fe(%rip),%edx # 0x600978 <[email protected]+2098528> 0x000000000040057a : mov 0x2003fc(%rip),%esi # 0x60097c <[email protected]+2098532> 0x0000000000400580 : mov $0x40068f,%edi 0x0000000000400585 : xor %eax,%eax 0x0000000000400587 : callq 0x4003f8 <[email protected]> ...
Bây giờ chúng ta biết rằng chức năng printf
sẽ nhận được ba thông số, và hai trong số đó là chỉ có bốn byte ra xa nhau. Đó là dấu hiệu tốt cho thấy hai biến này là các biến số a
và b
. Vì vậy, địa chỉ của a
là 0x600978 hoặc 0x60097c. Hãy tìm hiểu bằng cách cố gắng:
(gdb) x/w 0x60097c 0x60097c <[email protected]+2098532>: 0x0000007b (gdb) x/w 0x600978 0x600978 <[email protected]+2098528>: 0x00000000
Vì vậy a
, biến được đọc trong lần đầu tiên, là tại địa chỉ 0x60097c (vì 0x0000007B là đại diện thập lục phân cho 123, mà chúng tôi đã nhập), và b
là 0x600978.
Vẫn còn trong trình gỡ lỗi, chúng tôi có thể sửa đổi biến a
ngay bây giờ và sau đó tiếp tục chương trình.
(gdb) set *(int *)0x60097c = 1234567 (gdb) continue
Quay trở lại chương trình yêu cầu chúng tôi nhập vào hai số:
$ ./ab a: 123 a = 123 b: 5 a = 1234567, b = 5 $
Điều này cho bạn địa chỉ ảo của bạn, chứ không phải là vật lý. –
Như một phần trả lời trước đó, các chương trình bình thường không cần phải lo lắng về các địa chỉ vật lý khi họ chạy trong một không gian địa chỉ ảo với tất cả các tiện nghi của nó. Hơn nữa, không phải mọi địa chỉ ảo đều có địa chỉ vật lý, có thể thuộc về các tệp được ánh xạ hoặc các trang được hoán đổi. Tuy nhiên, đôi khi nó có thể là thú vị để xem bản đồ này, ngay cả trong userland.
Vì mục đích này, hạt nhân Linux phơi bày ánh xạ tới vùng người dùng thông qua một tập hợp các tệp trong /proc
. Các tài liệu có thể được tìm thấy here. Tóm tắt ngắn:
/proc/$pid/maps
cung cấp danh sách ánh xạ địa chỉ ảo cùng với thông tin bổ sung, chẳng hạn như tệp tương ứng cho tệp được ánh xạ./proc/$pid/pagemap
cung cấp thêm thông tin về từng trang được ánh xạ, bao gồm cả địa chỉ thực nếu nó tồn tại.
This website cung cấp chương trình C loại bỏ ánh xạ của tất cả các quy trình đang chạy bằng giao diện này và giải thích về nó.
Ví dụ tối thiểu với các thử nghiệm: https://stackoverflow.com/questions/17021214/how-to-decode-proc-pid-pagemap-entries-in-linux/45126141#45126141 –
#include "stdio.h"
#include "unistd.h"
#include "inttypes.h"
uintptr_t vtop(uintptr_t vaddr) {
FILE *pagemap;
intptr_t paddr = 0;
int offset = (vaddr/sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
uint64_t e;
// https://www.kernel.org/doc/Documentation/vm/pagemap.txt
if ((pagemap = fopen("/proc/self/pagemap", "r"))) {
if (lseek(fileno(pagemap), offset, SEEK_SET) == offset) {
if (fread(&e, sizeof(uint64_t), 1, pagemap)) {
if (e & (1ULL << 63)) { // page present ?
paddr = e & ((1ULL << 54) - 1); // pfn mask
paddr = paddr * sysconf(_SC_PAGESIZE);
// add offset within page
paddr = paddr | (vaddr & (sysconf(_SC_PAGESIZE) - 1));
}
}
}
fclose(pagemap);
}
return paddr;
}
- 1. Làm thế nào để truy cập bộ nhớ không gian người dùng từ hạt nhân Linux?
- 2. Làm cách nào để lấy địa chỉ vật lý (MAC) của địa chỉ IP bằng C#?
- 3. Làm thế nào để ghi bộ nhớ không gian hạt nhân (địa chỉ vật lý) vào một tệp bằng O_DIRECT?
- 4. PAE (Mở rộng địa chỉ vật lý) cho phép không gian địa chỉ lớn hơn 4GB như thế nào?
- 5. Xử lý gián đoạn Linux trong không gian người dùng
- 6. Làm thế nào để mmap một bộ đệm hạt nhân Linux để không gian người dùng?
- 7. Hiệu năng memcpy kém trong không gian người dùng cho bộ nhớ vật lý mmap'ed trong Linux
- 8. Làm thế nào để vô hiệu hoá ngẫu nhiên không gian địa chỉ cho một nhị phân trên Linux?
- 9. C địa chỉ của một địa chỉ của một biến
- 10. Làm thế nào để tìm địa chỉ kết thúc của một hàm trong một prog C?
- 11. Nhận địa chỉ IP của người dùng
- 12. Làm thế nào để không thiết lập địa chỉ email của người dùng trong django social-auth
- 13. Làm thế nào để có được địa chỉ email của người dùng twitter với twitter api
- 14. Cách kiểm tra xem địa chỉ có thể đọc được trong ứng dụng không gian người dùng Linux
- 15. Tôi có thể viết-bảo vệ mọi trang trong không gian địa chỉ của một quy trình Linux không?
- 16. Phương pháp đúng để tìm kiếm người dùng AD theo địa chỉ email từ .NET
- 17. Làm thế nào để khởi tạo một biến địa phương trong Java chỉ một lần
- 18. Nhận địa chỉ email của người dùng từ tên người dùng qua PowerShell và WMI?
- 19. Tìm chỉ số của một nhân vật trong một chuỗi
- 20. Làm cách nào để trích xuất tên người dùng từ địa chỉ email bằng javascript?
- 21. Làm thế nào để thiết lập địa chỉ IP từ C trong linux
- 22. Làm thế nào để đọc đầu vào của người dùng thành một biến trong Bash?
- 23. Bật mạng vật lý nhiều người dùng theo số
- 24. Làm thế nào để dịch địa chỉ bộ nhớ ảo sang địa chỉ thực?
- 25. Làm thế nào để bạn có được số điện thoại của một người từ sổ địa chỉ?
- 26. Làm thế nào để có được tổng bộ nhớ vật lý trong Bash để gán nó cho một biến?
- 27. Làm thế nào để giao tiếp với một mô-đun hạt nhân Linux từ không gian người dùng mà không cần xả rác/dev với các nút mới?
- 28. Chỉ số không gian cho các tọa độ địa lý?
- 29. Làm thế nào để đặt biến môi trường chỉ trong khoảng thời gian của tập lệnh?
- 30. Làm thế nào để loại bỏ một hiện vật dự án từ repo maven địa phương?
Có lẽ với/dev/mem? – user2284570
Một số thông tin có liên quan trong http://stackoverflow.com/questions/5748492/is-there-any-api-for-determining-the-physical-address-from-virtual-address-in-li –