2015-11-02 57 views
5

Mục tiêu của tôi là thiết bị AOSP để tự động ghi nhật ký tất cả cuộc gọi java hoặc JNI từ ứng dụng được nhắm mục tiêu, có hoặc không có đối số và giá trị trả về. Tôi không muốn sửa đổi ứng dụng, đó là lý do tại sao tôi đang tìm cách sửa đổi mã nguồn Android. Tôi không có kinh nghiệm với AOSP và vô số các thư viện và khung công tác của tôi vì vậy tôi đang tìm kiếm lời khuyên vì tôi không biết bắt đầu từ đâu. Hơn nữa, vì số lượng dòng tiềm năng được ghi lại, quá trình này phải hiệu quả (nghĩa là tôi không tin rằng một phương pháp giống như gỡ lỗi, nơi người ta phải thực hiện một lớp móc cho mỗi phương pháp nối, có thể hoạt động)Ứng dụng Android: java/JNI gọi chiến lược hooking

Điều gì Tôi đã hiểu cho đến nay:

Với hệ thống ART tương đối mới, nó biên dịch mã nguồn ứng dụng DEX thành một loại mã thực thi máy (OAT?) Và nó phức tạp hơn với công cụ so với Dalvik.

Luồng thực thi: bytecode java được biên dịch của ứng dụng (phụ thuộc vào API Android đã biên dịch) + libs.so -> DVM -> máy ảo Zygote phân chia -> Thực thi ứng dụng.

Nếu tôi cố gắng móc vào thư mục gốc (Android API + libs.so), nó sẽ yêu cầu số lượng công việc khó tính để thu hút từng cuộc gọi. Lý tưởng sẽ là một nơi mà tất cả các cuộc gọi java đi qua. Liệu một điểm như vậy có tồn tại với ART không?

Mã nguồn AOSP khó hiểu vì dường như không có tài liệu nào nêu rõ vai trò của từng tệp nguồn trong kiến ​​trúc toàn cầu. Vì vậy, nơi nó là tốt hơn để móc các cuộc gọi?

EDIT (s)

Chủ đề này đã không được bảo hiểm, vì vậy tôi sẽ hiển thị thông tin cho bất cứ ai quan tâm.

Các nghiên cứu của tôi đã xem qua blog này: http://blog.csdn.net/l173864930/article/details/45035521. (+ Google dịch) Ai liên kết đến dự án hooking gọi là Java và ELF thú vị này: https://github.com/boyliang/AllHookInOne

Nó không chính xác những gì tôi đang tìm kiếm, nhưng tôi sẽ cố gắng thực hiện bản vá AOSP để phân tích động phù hợp với nhu cầu của tôi.

Trả lời

9

Tôi đã thành công trong việc trả lời câu hỏi của mình. Đối với những gì tôi có thể hiểu được từ mã nguồn có 3 điểm vào tốt cho các cuộc gọi java:

  • ArtMethod :: Gọi (nghệ thuật/runtime/gương/art_method.cc)
  • Execute (nghệ thuật/runtime /interpreter/interpreter.cc)
  • DoCall (nghệ thuật/runtime/phiên dịch/interpreter_common.cc)

ArtMethod :: Invoke dường như được sử dụng cho phản xạ và cho gọi phương thức trực tiếp với một con trỏ đến OAT phần mã. (Một lần nữa, không có tài liệu, nó có thể không chính xác).

Thực hiện kết thúc cuộc gọi DoCall nói chung.

Có một số tối ưu hóa ART làm cho việc nghiên cứu các cuộc gọi Java trở nên khó khăn, như phương thức nội tuyến và gọi địa chỉ offset trực tiếp.

Bước đầu tiên là vô hiệu hóa những tối ưu hóa:

Trong thiết bị/thương hiệu/mô hình/device.mk (trong trường hợp thiết bị của tôi/LGE/búa/device.mk cho một mối quan hệ 5):

Thêm tùy chọn "chỉ diễn giải" vào dex2oat. Với tùy chọn này, ART chỉ biên dịch classpath khởi động, vì vậy các ứng dụng sẽ không được biên dịch trong OAT.

PRODUCT_PROPERTY_OVERRIDES := \ 
    dalvik.vm.dex2oat-filter=interpret-only 

Bước thứ hai là để vô hiệu hóa nội tuyến trong nghệ thuật/biên dịch/dex/frontend.cc:

Bỏ ghi chú "kSuppressMethodInlining".

/* Default optimizer/debug setting for the compiler. */ 
static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations 
    (1 << kLoadStoreElimination) | 
    // (1 << kLoadHoisting) | 
    // (1 << kSuppressLoads) | 
    // (1 << kNullCheckElimination) | 
    // (1 << kClassInitCheckElimination) | 
    (1 << kGlobalValueNumbering) | 
    // (1 << kPromoteRegs) | 
    // (1 << kTrackLiveTemps) | 
    // (1 << kSafeOptimizations) | 
    // (1 << kBBOpt) | 
    // (1 << kMatch) | 
    // (1 << kPromoteCompilerTemps) | 
    // (1 << kSuppressExceptionEdges) | 
    (1 << kSuppressMethodInlining) | 
    0; 

Bước cuối cùng là để vô hiệu hóa đang bù đắp gọi trực tiếp trong nghệ thuật/biên dịch/lái xe/compiler_driver.cc:

-bool use_dex_cache = GetCompilerOptions().GetCompilePic(); 
+bool use_dex_cache = true; 

Với những thay đổi các cuộc gọi tất cả khác nhau sẽ rơi vào các chức năng DoCall nơi chúng ta có thể cuối cùng thêm thói quen ghi nhật ký được nhắm mục tiêu của chúng tôi.

Trong nghệ thuật/runtime/phiên dịch/interpreter_common.h, thêm ngay từ đầu trong những bao gồm:

#ifdef HAVE_ANDROID_OS 
#include "cutils/properties.h" 
#endif 

Trong nghệ thuật/runtime/phiên dịch/interpreter_common.cc, thêm vào đầu của hàm DoCall:

#ifdef HAVE_ANDROID_OS 
    char targetAppVar[92]; 
    property_get("target.app.pid", targetAppVar, "0"); 

    int targetAppPID = atoi(targetAppVar); 

    if(targetAppPID != 0 && targetAppPID == getpid()) 
    LOG(INFO) << "DoCall - " << PrettyMethod(method, true); 
#endif 

Để nhắm mục tiêu ứng dụng tôi sử dụng thuộc tính đặt pid được nhắm mục tiêu. Đối với điều này chúng ta cần hệ thống lib/core/libcutils và lib này chỉ có sẵn khi AOSP được biên dịch cho một điện thoại thực (mà không gây rối với các makefiles hiện tại).
Vì vậy, giải pháp sẽ không hoạt động đối với trình giả lập. ( Chỉ đoán, không bao giờ thử EDIT: đã xác nhận, "cutils/properties.h" không thể được thêm vào bản dựng trình mô phỏng).

Sau khi biên dịch và nhấp nháy AOSP đã vá, khởi động ứng dụng, ps | grep cho việc tìm kiếm các PID và thiết lập thuộc tính trong root:

[email protected]:/ # ps | grep contacts          
u0_a2  4278 129 1234668 47356 ffffffff 401e8318 S com.android.contacts 

[email protected]:/ # setprop target.app.pid 4278 

[email protected]:/ # logcat 
[...] 
I/art  (4278): DoCall - int android.view.View.getId() 
I/art  (4278): DoCall - void com.android.contacts.activities.PeopleActivity$ContactsUnavailableFragmentListener.onCreateNewContactAction() 
I/art  (4278): DoCall - void android.content.Intent.<init>(java.lang.String, android.net.Uri) 
I/art  (4278): DoCall - void android.app.Activity.startActivity(android.content.Intent) 
I/ActivityManager( 498): START u0 {act=android.intent.action.INSERT dat=content://com.android.contacts/contacts cmp=com.android.contacts/.activities.ContactEditorActivity} from uid 10002 on display 0 
V/WindowManager( 498): addAppToken: AppWindowToken{3a82282b token=Token{dc3f87a ActivityRecord{c0aaca5 u0 com.android.contacts/.activities.ContactEditorActivity t4}}} to stack=1 task=4 at 1 
I/art  (4278): DoCall - void android.app.Fragment.onPause() 
I/art  (4278): DoCall - void com.android.contacts.common.list.ContactEntryListFragment.removePendingDirectorySearchRequests() 
I/art  (4278): DoCall - void android.os.Handler.removeMessages(int) 
I/art  (4278): DoCall - void com.android.contacts.list.ProviderStatusWatcher.stop() 
I/art  (4278): DoCall - boolean com.android.contacts.list.ProviderStatusWatcher.isStarted() 
I/art  (4278): DoCall - void android.os.Handler.removeCallbacks(java.lang.Runnable) 
I/art  (4278): DoCall - android.content.ContentResolver com.android.contacts.ContactsActivity.getContentResolver() 
I/art  (4278): DoCall - void android.content.ContentResolver.unregisterContentObserver(android.database.ContentObserver) 
I/art  (4278): DoCall - void android.app.Activity.onPause() 
I/art  (4278): DoCall - void android.view.ViewGroup.drawableStateChanged() 
I/art  (4278): DoCall - void com.android.contacts.ContactsActivity.<init>() 
I/art  (4278): DoCall - void com.android.contacts.common.activity.TransactionSafeActivity.<init>() 
I/art  (4278): DoCall - void android.app.Activity.<init>() 
I/art  (4278): DoCall - void com.android.contacts.util.DialogManager.<init>(android.app.Activity) 
I/art  (4278): DoCall - void java.lang.Object.<init>() 
[...] 

Khi nó kết thúc:

[email protected]:/ # setprop target.app.pid 0

Voila!

Quá tải không đáng chú ý từ quan điểm của người dùng, nhưng bản ghi nhật ký sẽ được điền nhanh chóng.

PS: Đường dẫn tệp và tên khớp với phiên bản Android 5 (Lollipop), chúng có thể khác với phiên bản cao cấp.

PS ': Nếu người ta muốn in các đối số của các phương pháp, tôi sẽ khuyên bạn nên xem art/runtime/utils.cc cho phương thức PrettyArguments và tìm một số thực hiện thực tế ở đâu đó trong mã.

+0

Cảm ơn bạn rất nhiều vì đã giải thích điều này. Tôi có một câu hỏi. Nếu tôi muốn vá mã AOSP khi bạn giải thích và xây dựng hình ảnh hệ thống Android cho trình mô phỏng, tôi nên thêm tùy chọn "chỉ diễn giải" ở đâu? Tôi không thể tìm thấy tệp device.mk cho trình mô phỏng. Vui lòng cho tôi biết. – aMa

+0

Thiết bị mục tiêu của bạn là gì? Tôi là một hammerhead nexus 5 nên con đường của tôi là /device/lge/hammerhead/device.mk. –

+0

Sry, tôi vừa đọc quá nhanh. Tôi chưa bao giờ thử làm giả lập và có thể bạn sẽ gặp phải các vấn đề với libcutils cho hàm property_get. Bạn đã thử mà không có sự sửa đổi của device.mk chưa? Nó sẽ làm việc mà không có nó trong trường hợp xấu nhất. Nếu không có nó, điều tồi tệ nhất có thể xảy ra là bạn bỏ lỡ một số cuộc gọi. –

2

Có lẽ bạn có thể lấy thêm ý tưởng từ dự án Xposed, nó làm theo phương pháp tương tự bằng cách tắt các phương pháp nội tuyến và trực tiếp tối ưu hóa phân nhánh:

https://github.com/rovo89/android_art/commit/0f807a65612f77a46120a53d3caa12c2

https://github.com/rovo89/android_art/commit/92e8c8e0309c4a584f4279c478d54d8ce036ee59

+0

Thx vì sự quan tâm của bạn. Tôi đã biết dự án Xposed. Trên thực tế, sau khi tôi tìm thấy làm thế nào để vô hiệu hóa nội tuyến, tôi tìm thấy các dự án github và tôi kiểm tra mỗi git cam kết. Tôi làm thế nào tôi tìm thấy để vô hiệu hóa những gì bạn gọi là phân nhánh trực tiếp, tất cả các khoản tín dụng cho điều này đi cho tác giả (s) của Xposed. –

Các vấn đề liên quan