DexPatcher: แก้ไข APK ของ Android โดยใช้ Java

DexPatcher ช่วยให้นักพัฒนาสามารถแก้ไข APK โดยใช้ Java สิ่งนี้มีข้อดีหลายประการ และการใช้ DexPatcher นั้นง่ายกว่าวิธี Smali แบบคลาสสิกมาก

คุณอาจเคยเห็นหรือติดตั้งแอปพลิเคชั่นที่ถูกดัดแปลง ไม่ว่าจะเป็นตัวเรียกเลขหมายที่ได้รับแพตช์สำหรับความละเอียดของคุณ หรือเวอร์ชัน WhatsApp แบบกำหนดเองพร้อมคุณสมบัติเพิ่มเติม นักพัฒนาทำเช่นนั้นได้อย่างไร? หลายครั้งที่ซอร์สโค้ดของแอปพลิเคชันไม่พร้อมใช้งาน ดังนั้นมันทำงานอย่างไร เราจะเห็นสิ่งนั้นก่อน จากนั้นจึงมาดูเครื่องมือใหม่ที่มีจุดมุ่งหมายเพื่อทำให้กระบวนการง่ายขึ้นมาก และสุดท้ายก็เปรียบเทียบกับเฟรมเวิร์ก Xposed ยอดนิยมเพื่อดูว่ามันแตกต่างกันอย่างไร

คุณอาจเคยได้ยินเกี่ยวกับวิธีแก้ไข APK ตามปกติ นักพัฒนาซอฟต์แวร์เสียบปลั๊กตัวเองเข้ากับ เมทริกซ์ เริ่มมองเห็นทุกสิ่งใน Smali และได้รับความสามารถในการแก้ไขสิ่งต่าง ๆ โดยใช้พลังของ แหล่งที่มา. การโทรศัพท์ก็เพียงพอแล้วที่จะพาพวกเขาออกไปเมื่อเสร็จแล้ว เมื่อถึงจุดนี้พวกเขาก็พร้อมที่จะแชร์ APK ใหม่ที่สดใส

จริงจังกว่านี้… มาเริ่มกันตั้งแต่ต้นเลย หากคุณไม่คุ้นเคยกับการดัดแปลงแอปพลิเคชัน Android คุณอาจสงสัยว่า smali คืออะไร นักพัฒนามักจะใช้ภาษาการเขียนโปรแกรม Java เพื่อเขียนโค้ดแอพ Android จากนั้นโปรแกรม (คอมไพลเลอร์) จะ "แปล" โค้ดนั้นเป็นรูปแบบอื่นที่เหมาะกับอุปกรณ์ของคุณ ส่งผลให้ได้ไฟล์ .dex อยู่ภายในแพ็คเกจแอปพลิเคชัน (หรือ APK)

เมื่อถึงจุดนั้น คุณจะไม่สามารถเข้าถึงซอร์สโค้ดต้นฉบับได้อีกต่อไป (เว้นแต่คุณจะเป็นนักพัฒนาหรือแอปพลิเคชันนั้นเป็นโอเพ่นซอร์ส) อย่างไรก็ตาม สิ่งที่คุณมีคือ APK เนื่องจากเป็นสิ่งที่ติดตั้งบนอุปกรณ์ของคุณ จากนั้น คุณจะได้รับไฟล์ dex (โดยปกติจะเป็น class.dex) จากนั้นลองแปลกลับเป็นรูปแบบที่คุณเข้าใจได้ นั่นคือที่มาของ smali ซึ่งเป็นคำแปลที่อ่านง่ายแต่น่าเชื่อถือ คุณสามารถก้าวไปอีกขั้นหนึ่งแล้วแปลกลับเป็น Java แม้ว่ากระบวนการนั้นจะไม่น่าเชื่อถือเพียงพอ แต่คุณจะได้รับ ผลลัพธ์ที่เข้าใจได้ แต่มีโอกาสที่คุณจะแปลอย่างอื่นไม่ได้อีกครั้ง เนื่องจากรายละเอียดบางอย่างจะหายไป ระหว่างทาง. กล่าวอีกนัยหนึ่ง การปรับเปลี่ยนใด ๆ ที่คุณอาจทำนั้นไร้ประโยชน์เพราะคุณจะไม่สามารถเปลี่ยนมันกลับเป็น APK อีกครั้งเพื่อติดตั้งมันบนอุปกรณ์ของคุณได้… อย่างน้อยก็โดยไม่ต้องใช้ความพยายามมากนัก

smali/baksmali จริงๆ แล้วเป็นแอสเซมเบลอร์/ดิสเซมเบลอร์สำหรับรูปแบบ dex นั่นคือสิ่งที่ความหมายในภาษาไอซ์แลนด์อย่างแท้จริง อย่างไรก็ตาม เรามักจะใช้รูปแบบที่ smali เข้าใจเมื่อเราพูดว่า 'Smali' (ให้คิดซะว่าเป็นคำสั่ง) การกำหนดรายละเอียดเล็กๆ น้อยๆ ทุกๆ อย่าง แม้ว่ามนุษย์จะไม่จำเป็นทั้งหมดก็ตาม ดังนั้นจึงละเอียดมากกว่า ชวา) โปรดทราบว่าคำอธิบายข้างต้นนั้นเรียบง่ายเล็กน้อย แต่ควรเป็นการเปรียบเทียบที่ใกล้เคียงแต่ยังคงเข้าใจได้ง่าย

นักพัฒนาจะต้องทำอะไรเพื่อแก้ไขแอป (โดยไม่ต้องเข้าถึงแหล่งที่มา) แล้ว? กระบวนการมีมากหรือน้อยดังนี้:

  1. รับ APK (จากเว็บหรือจากอุปกรณ์)
  2. ใช้บางอย่างเช่น apktool.apk เพื่อถอดรหัส APK เป็น Smali (apktool.apk ใช้ smali/baksmali แต่ช่วยให้ถอดรหัสและสร้าง APK ใหม่ได้ง่ายขึ้นมาก และยังดูแลทรัพยากรการถอดรหัสเช่นไฟล์ XML ด้วย)
  3. แยก class.dex ออกจาก APK แล้วใช้ เดกซ์2จาร์ และสุดท้ายคือตัวถอดรหัส Java เพื่อรับโค้ด Java (ไม่สมบูรณ์ ใช้งานไม่ได้บ่อย แต่ส่วนใหญ่เข้าใจได้) (นี่เป็นทางเลือก แต่อาจมีประโยชน์ได้เนื่องจาก Smali เข้าใจยากกว่ามาก)
  4. ระบุสิ่งที่จะแก้ไข
  5. แก้ไขจริงโดยแก้ไขโค้ด Smali โดยตรง
  6. อีกทางหนึ่ง เขียนการแก้ไขใน Java คอมไพล์ แยกส่วนอีกครั้งเป็น Smali จากนั้นคัดลอกโค้ด Smali ที่เป็นผลลัพธ์ไปทับ
  7. เสร็จแล้วก็ใช้เลย apktool.apk อีกครั้งเพื่อสร้าง APK ใหม่
  8. ลงนาม APK (เพื่อยืนยันตัวตนของผู้แต่ง ต้องลงนามแพ็คเกจทั้งหมด) และสุดท้ายจึงทำการติดตั้ง

การเขียนโค้ด Smali ค่อนข้างยากและมีแนวโน้มที่จะเกิดข้อผิดพลาด การเปลี่ยนแปลงเล็กๆ น้อยๆ สามารถทำได้ใน Smali แต่การเพิ่มคุณสมบัติใหม่ๆ เข้าไปนั้นเป็นเรื่องที่ท้าทายยิ่งกว่า นอกจากนี้ คุณจะไม่มีข้อผิดพลาดด้านเวลาคอมไพล์ ดังนั้นแม้แต่การพิมพ์ผิดก็อาจตรวจพบได้เฉพาะตอนรันไทม์เท่านั้น การขยายและการแชร์แพตช์ Smali อาจเป็นปัญหาได้เช่นกัน เนื่องจากส่วนต่างมักจะมีความเฉพาะเจาะจงกับ APK เวอร์ชันใดเวอร์ชันหนึ่งโดยเฉพาะ แม้ว่าจะมีเครื่องมือบางอย่างเพื่อทำให้กระบวนการบางส่วนที่อธิบายข้างต้นง่ายขึ้น (คุณธรรมสิบสตูดิโอ อยู่ในใจ) ก็ยังน่าเบื่อได้

DexPatcher โดย XDA Senior Member แลนชอน มีเป้าหมายเพื่อแก้ไขปัญหาเหล่านี้ โดยทำให้กระบวนการง่ายขึ้น และช่วยให้นักพัฒนาหลีกเลี่ยงการติดต่อกับ Smali ได้อย่างสมบูรณ์ นักพัฒนาซอฟต์แวร์สามารถเขียนแพตช์ใน Java เพียงอย่างเดียวและให้ DexPatcher จัดการทุกอย่างแทน

นี่เป็นข้อได้เปรียบหลักในการมีไฟล์แพตช์ที่อ่านและจัดการได้ง่าย การแพตช์ APK โดยทั่วไปจะสะดวกยิ่งขึ้น เราจะเห็นตัวอย่างเต็มเกี่ยวกับวิธีใช้ DexPatcher ในอีกสักครู่ แต่ต่อไปนี้เป็นภาพรวมโดยย่อเกี่ยวกับสิ่งที่นำเสนอก่อน:

  • โอเพ่นซอร์ส.
  • ข้ามแพลตฟอร์ม: ควรทำงานบน Linux, Mac และ Windows
  • ไฟล์แพทช์: การแก้ไขที่คุณทำจะอยู่ในไฟล์แพทช์ Java ที่คุณสามารถแชร์ได้อย่างอิสระ
  • Java: ไม่ใช่ Smali

คุณยังได้รับประโยชน์จากการตรวจสอบข้อผิดพลาดตามเวลาบิลด์ด้วย ดังนั้นจุดบกพร่องจึงปรากฏขึ้นตั้งแต่ช่วงต้นของวงจรการพัฒนา การคอมไพล์ Java ให้การตรวจสอบเวลาการคอมไพล์ตามปกติ (พร้อมการเข้าถึงสัญลักษณ์ APK ดั้งเดิม) และ DexPatcher บังคับใช้ ความเข้ากันได้ของแหล่งที่มาและแพตช์เมื่อทำการแพตช์ การให้ข้อมูลที่เป็นประโยชน์ และคำเตือนเมื่อดูเหมือนว่าคุณกำลังทำอะไรบางอย่าง ถูกกฎหมายแต่คาว

นอกจากนั้น DexPatcher ยังมาพร้อมกับชุดของ สคริปต์ตัวช่วย (ใช้ได้เฉพาะบน Linux แม้ว่าสามารถย้ายไปยังแพลตฟอร์มอื่นได้เช่นกัน) สิ่งเหล่านี้ดูแลการตั้งค่าพื้นที่ทำงาน แยกคลาสและทรัพยากรของ APK เป้าหมาย แยกคลาสเป็น Java ( ตัวถอดรหัส CFR Java ใช้สำหรับอย่างหลัง) และในที่สุดก็สร้างและลงนาม APK ที่ได้รับแพตช์เมื่อคุณทำเสร็จแล้ว

ลองมาดูตัวอย่าง (บน Linux):

ติดตั้งสคริปต์ DexPatcher

$# Make a directory where we can test stuff out and enter it. 

$ mkdir xda-test

$cd xda-test

$ git clone https://github.com/Lanchon/DexPatcher-scripts.git dexpatcher # Clone the DexPatcher helper scripts repo.

$cd dexpatcher

$ chmod +x dxp-* # Not necessary, but for clarity: we need to make sure the files we'll call later are executable.

กำหนดค่าสคริปต์ DexPatcher

เปิด dxp.config ในโปรแกรมแก้ไขข้อความที่คุณชื่นชอบ และตรวจสอบให้แน่ใจว่าได้เปลี่ยนตัวแปรที่จำเป็นเพื่อให้เหมาะกับระบบของคุณ คุณจะต้องเปลี่ยนบรรทัดต่อไปนี้เพื่อชี้ไปที่ตำแหน่งการติดตั้ง Android SDK ของคุณแทน:

dxp_android_sdk_dir=(~/android/sdk)

(DexPatcher จะเลือกเวอร์ชันแพลตฟอร์มสูงสุดที่มีอยู่โดยอัตโนมัติ นอกจากนี้ คุณยังสามารถแก้ไขตัวเลือกการกำหนดค่าอื่นๆ เพื่อให้ใช้เครื่องมือบางอย่างในเวอร์ชันของคุณเองแทนค่าเริ่มต้นที่รวมไว้ได้)

เพื่อความสะดวกในการเข้าถึงเราสามารถเพิ่ม เดกซ์แพตเชอร์ ไดเรกทอรีของเรา เส้นทางหรือแม้แต่เชื่อมโยงส่วนต่างๆ เข้าด้วยกัน dxp-* สคริปต์ไปยังตำแหน่งที่มีอยู่ในของคุณแล้ว เส้นทาง, เช่น ~/bin:

export PATH=$PWD:$PATH

ปรับเปลี่ยนแอปพลิเคชัน

สำหรับตัวอย่างนี้ เราจะใช้แอปพลิเคชันโอเพ่นซอร์สที่เรียบง่าย แน่นอนว่าการแพตช์ซอร์สโค้ดโดยตรงอาจทำได้ในกรณีนี้ แต่นั่นไม่สนุกเลย!

เราจะนำแอปพลิเคชัน "Get ID" โดย basil2style ซึ่งเป็นแอปพลิเคชันที่แสดงรายละเอียดบางอย่างเกี่ยวกับอุปกรณ์ของคุณ เป้าหมายของเราคือการแก้ไขปุ่ม "คัดลอก" สำหรับ "รหัสอุปกรณ์" และให้ปุ่มแชร์รหัสนี้แทน:

  • ก่อนอื่น มาดาวน์โหลด APK ที่เราจะแก้ไขกันก่อน: รับบัตรประจำตัว.
  • ถอดรหัสแอปพลิเคชัน
  • สร้างคีย์การลงนามที่เราจะใช้ในภายหลังเพื่อลงนาม APK

เรายังสามารถทำได้ทั้งหมดผ่านเชลล์ โดยใช้สคริปต์ตัวช่วย:

$cd dexpatcher # Go to our working directory. 

$ curl -O https://f-droid.org/repo/makeinfo.com.getid_1.apk # Download the APK.

$ dxp-setup-for-apk makeinfo.com.getid_1.apk # Unpack and decompile the APK.

$cd makeinfo.com.getid_1 # Go to the newly created directory where everything is unpacked/decompiled to.

$ dxp-create-keystore # Create the APK signing key. Press 6 times (or fill out the info), then "yes".

คุณจะสังเกตเห็นไดเร็กทอรีที่แตกต่างกันสองสามรายการในนั้น:

  • ถอดรหัส: คุณจะพบทรัพยากรและ Smali ที่นี่ตามที่ถอดรหัสโดย apktool.apk.
  • src: ไดเร็กทอรีว่างเปล่า นี่คือที่ที่เราจะวางไฟล์แพทช์ของเรา
  • src-cfr: ที่นี่คือที่ อ้างอิง ถอดรหัสแอป (พร้อมกับข้อผิดพลาด) เหมาะที่จะพิจารณาเพื่อตัดสินใจว่าจะเปลี่ยนแปลงอะไร (คุณอาจต้องใช้ทรัพยากรและ ID จากไดเร็กทอรีถอดรหัสด้านบน แต่ไม่ใช่สำหรับตัวอย่างนี้)
  • src-cfr-nodecode.src: เช่นเดียวกับข้างต้น แต่มีเพียงสตับที่ว่างเปล่า (ไม่มีรหัส มีเพียงโครงกระดูก) คุณสามารถใช้ไฟล์เหล่านี้เป็นพื้นฐานสำหรับแพทช์ของคุณได้ดังที่เราจะได้เห็นในอีกสักครู่

ดังที่เราได้กล่าวไปแล้ว เราต้องการเปลี่ยนปุ่ม "คัดลอก" ID อุปกรณ์เพื่อแชร์ข้อความ ID แทน หากเราดูซอร์สโค้ดเราจะสังเกตเห็นว่าปุ่มคัดลอกรหัสอุปกรณ์ (อุปกรณ์_คัดลอก) เมื่อคลิก เหตุการณ์ได้รับการจัดการโดยคลาสที่ไม่ระบุชื่อใน src-cfr/makeinfo/com/getid/MainActivity.java. แม้ว่าเราจะแก้ไขมันได้ที่นี่ แต่โดยปกติแล้วจะดีกว่าหากหาวิธีอื่น เนื่องจากคลาสที่ไม่ระบุตัวตนมีชื่อเป็นตัวเลข (MainClassName$SomeNumber, เช่น. กิจกรรมหลัก$3) ซึ่งอาจเปลี่ยนแปลงอย่างคาดเดาไม่ได้ระหว่างเวอร์ชันต่างๆ

แต่เราจะลงทะเบียนชั้นเรียนของเราเองสำหรับกิจกรรมโดยแก้ไข กิจกรรมหลัก ระดับ. ก่อนอื่น เรามาคัดลอกเวอร์ชัน "โครงกระดูก" กันก่อน src-cfr-nocode/makeinfo/com/getid/MainActivity.java ถึง src/makeinfo/com/getid/MainActivity.java (จำไว้ src คือที่ที่แพทช์ของเราจะอาศัยอยู่) (คุณสามารถคัดลอกเวอร์ชันพร้อมโค้ดเต็มได้หากต้องการ นี่เป็นเรื่องของรสนิยมเท่านั้น)

ตอนนี้เราสามารถแก้ไขได้ดังนี้:

  • เพิ่มการนำเข้าที่จำเป็นสำหรับคำอธิบายประกอบ DexPatcher:
importlanchon.dexpatcher.annotation.*;
  • เพิ่มแท็กเพื่อระบุว่าเรากำลังแก้ไขชั้นเรียน นอกจากนี้เรายังตั้งค่าการดำเนินการเริ่มต้นสำหรับสมาชิกของคลาสแพตช์ด้วย ไม่สนใจซึ่งหมายความว่าสมาชิกจะอยู่ที่นั่นเพื่อให้โค้ดของเราอ้างอิงในระหว่างการคอมไพล์ Java แต่ DexPatcher จะถูกละเลย
@DexEdit(defaultAction=DexAction.IGNORE)

publicclassMainActivity

// The reference to ActionBarActivity will be satisfied by symbols

// extracted from the app when we build the patch.

extendsActionBarActivity{

  • นอกจากนี้ ให้เพิ่มเนื้อหาว่างให้กับตัวสร้างและ ในการสร้าง วิธีการ เช่นเดียวกับวิธีการอื่นๆ ทั้งหมดที่เราวางแผนจะใช้ (โปรดจำไว้ว่าวิธีการเหล่านั้นจะถูกเพิกเฉยเมื่อมีการใช้โปรแกรมแก้ไขของเราจริง ๆ - เราเพียงเพิ่มวิธีการเหล่านั้นเพื่อให้เราสามารถอ้างอิงถึงได้ที่นี่ หากจำเป็น) คุณยังสามารถเพิ่มไฟล์ พื้นเมือง คำหลักแทน
  • ในตอนนี้เราสามารถสร้างแพตช์ได้แล้ว หากคุณสงสัย:
    $ dxp-make # Output: `patched.apk`.
    ค่อนข้างง่ายใช่มั้ย? ไปกันต่อ -- เรายังทำไม่เสร็จเลย
  • มาแก้ไขกัน ในการสร้าง ตอนนี้เพื่อกำหนดของตัวเอง OnClickListener เพื่อให้เราสามารถแชร์ ID อุปกรณ์แทนการคัดลอกไปยังคลิปบอร์ด:
    // Rename the target method so that we can still call it (the original)// if needed.@DexEdit(target="onCreate")protectedvoidsource_onCreate(Bundlevar1){}// Add our new custom method.@Override@DexAddprotectedvoidonCreate(Bundlevar1){// Call the original method:source_onCreate(var1);// Replace the text and handler:device_copy.setText("Share");device_copy.setOnClickListener(newDeviceCopyOnClick());}// Note that we don't use an anonymous class to avoid nameclashing with// MainActivity$1, which already exists.// We also could've defined a nested MainActivity.Patch class and used// an anonymous class in MainActivity.Patch.onCreate(), and then called// MainActivity.Patch.onCreate() from MainActivity.onCreate().@DexAddclassDeviceCopyOnClickimplementsView.OnClickListener{@OverridepublicvoidonClick(Viewobject){if(MainActivity.this.val){Intentintent=newIntent(Intent.ACTION_SEND);intent.setType("text/plain");intent.putExtra(Intent.EXTRA_SUBJECT,"Device ID");intent.putExtra(Intent.EXTRA_TEXT,device.getText().toString());startActivity(Intent.createChooser(intent,"Share Device ID"));}else{Toast.makeText(MainActivity.this.getApplicationContext(),"Nothing to Share",0).show();}}}
  • ดูเหมือนว่าเราจะเสร็จแล้ว! แพทช์เต็มควรมีลักษณะเช่นนี้ นี้. ตอนนี้เราสามารถสร้าง APK ที่ได้รับการแพตช์แล้วและติดตั้งได้:
    $ dxp-make$ adb install patched.apk
  • มาดูผลลัพธ์กัน:

(ขอบคุณ Lanchon ที่ช่วยในเรื่องโค้ดตัวอย่าง!)

Xposed ได้รับความนิยมอย่างมาก และด้วยเหตุผลที่ดี มันทำให้การสร้าง การแชร์ และติดตั้งม็อดง่ายขึ้นมากสำหรับนักพัฒนาและผู้ใช้ มีความแตกต่างเล็กน้อยระหว่าง DexPatcher และ Xposed ที่อาจทำให้บางคนชอบอย่างใดอย่างหนึ่งมากกว่าสิ่งอื่น:

  1. Xposed ทำสิ่งมหัศจรรย์ด้วยการเชื่อมโยงวิธีการต่าง ๆ ในขณะรันไทม์ และอนุญาตให้นักพัฒนาทำอะไรบางอย่างก่อน หลัง หรือแทนวิธีการใดก็ได้ ในทางกลับกัน DexPatcher จะแก้ไขทุกอย่างก่อนรันไทม์และสร้าง APK แบบสแตนด์อโลนที่ได้รับการแก้ไข -- การรันโค้ดก่อน, หลังหรือแทนเมธอดยังคงเป็นไปได้ และคุณมีอะไรเพิ่มเติมจริงๆ เสรีภาพ.
  2. การผลิต APK แบบสแตนด์อโลนหมายความว่าไม่ต้องอาศัยเฟรมเวิร์กภายนอกใดๆ นอกจากนี้ยังหมายความว่าไม่จำเป็นต้องรูทในการแก้ไขแอปของผู้ใช้
  3. เนื่องจากคุณสร้าง APK ใหม่ด้วย DexPatcher จึงจะมีการเซ็นชื่อแตกต่างออกไป ซึ่งหมายความว่าผู้ใช้ไม่สามารถรับการอัปเดตอย่างเป็นทางการจากผู้เขียนต้นฉบับ และอาจทำให้เกิดปัญหาบางอย่างกับแอป เช่น Google Apps หากตรวจสอบลายเซ็นแล้ว
  4. ซอร์สโค้ดของแพทช์ทั้งโมดูลและ DexPatcher สามารถแจกจ่ายและแก้ไขได้อย่างง่ายดาย พวกเขายังมีความคล้ายคลึงกันมากมายหากคุณคุ้นเคยบ้าง

เราได้พูดคุยเกี่ยวกับ DexPatcher มามากพอแล้ว ถึงเวลาที่คุณต้องลองดูแล้ว ดังนั้นตรงไปที่ หัวข้อฟอรัม DexPatcher เพื่อเริ่มต้นทันที!