綁定帳號登入

Android 台灣中文網

打印 上一主題 下一主題

[原創] 為無開放原始碼的核心編譯模塊

[複製連結] 查看: 37098|回覆: 1|好評: 0
跳轉到指定樓層
樓主
djpvd | 收聽TA | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
發表於 2019-9-16 10:37

馬上加入Android 台灣中文網,立即免費下載應用遊戲。

您需要 登錄 才可以下載或查看,沒有帳號?註冊

x
本帖最後由 djpvd 於 2019-9-16 10:41 編輯

有些廠商沒有公開 Kernel 原始碼,但可以下載 Linux 官方的原始碼來編譯模塊,其實安卓的核心就是 ARM 版的 Linux 核心,修改的範圍差異其實不大,加上一些廠商自訂的驅動而已,該死的是這些廠商的驅動,網路上幾乎找不到,沒發怖原始碼就沒辦法完整編譯核心。但模塊還是可以編譯,畢竟手機要外接的 USB 裝置,在 Linux 底下可以驅動,就有辦法移值到 Android 上面。只是把驅動的原始碼編譯成 ARM 版而已。

在沒有核心原始碼的狀況下,只能對 Kernel 打 Binrary Patch。才有辦法載入模塊。

編譯模塊的預先準備工作

## 提取手機內的核心配置
通常在 /proc/config.gz
提取出來解壓縮命名為 android_defconfig

打開手機設定內關於手機,檢查核心版本跟 gcc 版本,紀錄起來
如果是 gcc 4.9 就用 google 的版本,如果是 Linaro GCC 就到 Linaro 網站對應版本下載。
對應 GCC 版本來編譯,編譯的成功率比較大。


## 下載 Linux 核心原始碼對應手機的核心版本下載
http://ftp.ntu.edu.tw/linux/kernel/

  1. mkdir -p linux-kern
  2. cd linux-kern
複製代碼

  1. wget http://ftp.ntu.edu.tw/linux/kernel/v3.x/linux-3.10.61.tar.xz
  2. tar Jxvf linux-3.10.61.tar.xz
複製代碼



## 下載編譯工具
# Google GCC 4.9 範例 nougat 版本
# 編譯 armv7 32-bit 版本
  1. git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-X86/arm/arm-linux-androideabi-4.9 prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9 -b nougat-release --depth=1
複製代碼

# 編譯 armv8 64-bit 版本
  1. git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 -b nougat-release --depth=1
複製代碼


# Linaro GCC
https://releases.linaro.org/components/toolchain/binaries/
# 編譯 armv7 32-bit 版本
  1. wget https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/arm-eabi/gcc-linaro-6.3.1-2017.05-x86_64_arm-eabi.tar.xz
  2. tar Jxvf gcc-linaro-6.3.1-2017.05-x86_64_arm-eabi.tar.xz
複製代碼

# 編譯 armv8 64-bit 版本
  1. wget https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/aarch64-elf/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-elf.tar.xz
  2. tar Jxvf gcc-linaro-6.3.1-2017.05-x86_64_aarch64-elf.tar.xz
複製代碼



## 指定編譯器
修改 Makefile 檔案
# Google GCC ARMv7 32-bit
CROSS_COMPILE   ?= ../prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-
# Google GCC ARMv8 64-bit
CROSS_COMPILE   ?= ../prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-

# Linaro GCC ARMv7 32-bit
CROSS_COMPILE   ?= ../gcc-linaro-6.3.1-2017.05-x86_64_arm-eabi/bin/arm-eabi-
# Linaro GCC ARMv8 64-bit
CROSS_COMPILE   ?= ../gcc-linaro-6.3.1-2017.05-x86_64_aarch64-elf/bin/aarch64-elf-

## 核心配置
把提取出來的手機配置文件 android_defconfig,如果是 armv8 64-bit 核心就放到 arch/arm64/configs/ 裡面
如果是 armv7 32-bit 核心就放到 arch/arm/configs/ 裡面。

  1. cd linux-3.10.61

  2. make clean
複製代碼


# 配置 armv7 32-bit 版本
  1. make ARCH=arm android_defconfig
  2. make ARCH=arm menuconfig
複製代碼


# 配置 armv8 64-bit 版本
  1. make ARCH=arm64 android_defconfig
  2. make ARCH=arm64 menuconfig
複製代碼


選擇自己需要的模塊驅動就好,不必全部編譯。

# MAC80211 網路驅動
Networking support > Wireless
    <M> Generic IEEE 802.11 Networking Stack (mac80211)
模塊 mac80211.ko


# USB Modem 驅動
Device Drivers > USB support
    <M> USB Modem (CDC ACM) support
模塊 cdc-acm.ko


# USB ATAPI 驅動
Device Drivers > USB support
    <M> Freecom USB/ATAPI Bridge support
模塊 ums-freecom.ko


# USB 無線網卡驅動
Device Drivers > Network device support > Wireless LAN
選擇需要的驅動
範例: Atheros 晶片無線網卡
<M> Atheros Wireless Cards  --->
    <M>   Atheros 802.11n wireless cards support (Atheros ath9k)
    <M>   Atheros HTC based wireless cards support (Atheros ath9k HTC)
    <M>   Linux Community AR9170 802.11n USB support

    <M>   Atheros mobile chipsets support
    <M>   Atheros ath6kl SDIO support
    <M>   Atheros ath6kl USB support

    <M>   Atheros AR5523 wireless driver support

    <M>   Atheros 802.11ac wireless cards support (Atheros ath10k)
    <M>   Qualcomm Atheros WCN3660/3680 support


# USB 藍芽驅動
Networking support > Bluetooth subsystem support > Bluetooth device drivers
<M> HCI USB driver
<M> HCI UART driver
<M> HCI BCM203x USB driver
<M> HCI BPA10x USB driver
<M> HCI BlueFRITZ! USB driver


# USB 網卡驅動
Device Drivers > Network device support > USB Network Adapters
<M> USB Pegasus/Pegasus-II based ethernet device support
<M> USB RTL8150 based ethernet device support
<M> Realtek RTL8152 Based USB 2.0 Ethernet Adapters

設置好之後,選擇 SAVE 保存設定,然後選擇 EXIT 退出。

# mac80211 注入 Patch
  1. wget https://raw.githubusercontent.com/Mint-Fans/linux-package/kali/mac80211.patch
  2. patch -p0 -i mac80211.patch
複製代碼


## 編譯
# armv7 32-bit 版本編譯
  1. make -j$(nproc) ARCH=arm
複製代碼

# armv8 64-bit 版本編譯
  1. make -j$(nproc) ARCH=arm64
複製代碼


## 安裝模塊
  1. export INSTALL_MOD_PATH=$(pwd)/out
複製代碼


# armv7 32-bit 版本安裝
  1. make -j$(nproc) ARCH=arm modules_install
複製代碼

# armv8 64-bit 版本安裝
  1. make -j$(nproc) ARCH=arm64 modules_install
複製代碼


編譯完成後檔案在 out 目錄下


「用Android 就來APK.TW」,快來加入粉絲吧!
Android 台灣中文網(APK.TW)

評分

參與人數 1碎鑽 +1 幫助 +1 收起 理由
a0953254986 + 1 + 1 讚一個!

查看全部評分

收藏收藏 分享分享 分享專題
用Android 就來Android 台灣中文網(https://apk.tw)
回覆

使用道具 舉報

沙發
 樓主| djpvd | 收聽TA | 只看該作者
發表於 2019-9-16 12:00
本帖最後由 djpvd 於 2019-9-18 09:46 編輯

Kernel Binrary Patch
準備工具:
HEX 編輯器:看自己那一款上手,個人使用 HxD
Debuger: IDA Pro 或者 Hopper Disassembler。
推薦 Hopper Disassembler,因為可以直接修改 arm 操作代碼。Windows 平台下修改可能不是很適合。

boot.img 解壓縮將核心提取出來,有些核心有壓縮,有些沒壓縮。要如何檢查?
用 HEX 編輯器打開 核心(boot.img-zImage) 找尋字串 Linux version 。有找到就是沒壓縮。沒找到就是已壓縮。
Linux 底下可以用 $ strings boot.img-zImage | grep "Linux version"  來檢查。

這裡只說 gzip 壓縮的範例
具體可以參考 https://www.xmsec.cc/re-modify-kernel-bypass-antidebug/

gzip 壓縮的核心應該分三段

---------------
第一段雜質
---------------
piggy.gz
---------------
第三段雜質
---------------

piggy.gz 就是已壓縮的核心,就是要提取這段出來解壓縮。

最好用 HEX 編輯器 把第二段取出來,用 dd 提取的話,後面會包含第三段雜質。這個自己壓個 gzip 檔案去比較看看就知道,第三段雜質從那開始。
取出原本的 piggy.gz 是要知道他的大小,因為修改後重新打包的 piggy.gz 不可以比原來的大。因為覆蓋到第三段雜質,手機會無法啟動。


# 取得 zImage 裡面 piggy.gz 的開始偏移量
OPS=$(LC_ALL=C grep -a -b -o $"x1fx8bx08x00"  boot.img-zImage | cut -d ":" -f 1)
printf "0x%x" $OPS

把偏移量記錄下來,後面要覆寫 boot.img-zImage 用。

# 從 boot.img-zImage 解壓縮核心
OPS=$(LC_ALL=C grep -a -b -o $"x1fx8bx08x00"  boot.img-zImage | cut -d ":" -f 1)
dd if=boot.img-zImage bs=1 skip=$OPS | zcat > piggy

解壓縮好之後就要開始進入重點了。


# 用 Debuger 分析 piggy
通常從手機提取的 Kernel 都已經去掉符號,所以最好把先前編譯模塊的原始碼裡面 kernel/ 目錄下的 module.c module.o 做參考
module.o 可以用 Debuger 打開分析 這個有帶符號。

Kernel 要修改的部份是原本編進核心內的 module.o 部份。

原始碼修改的參考:

* 去除模塊CRC效驗
module.c

函數 check_version

bad_version:
        pr_warn("%s: disagrees about version of symbol %s", mod->name, symname);
        return 0;

必須讓 bad_version  return 1

* 去掉 setup_load_info 函數裡面的 return ERR_PTR(-ENOEXEC);

* 去除模塊 vermagic 字串驗證
函數 check_modinfo
        /* This is allowed: modprobe --force will invalidate it. */
        if (!modmagic) {
                err = try_to_force_load(mod, "bad vermagic");
                if (err)
                        return err;
        } else if (!same_magic(modmagic, vermagic, info->index.vers)) {
                pr_err("%s: version magic "%s" should be "%s"
",
                       mod->name, modmagic, vermagic);
                return -ENOEXEC;
        }

去掉 return err 跟 return -ENOEXEC;

以上是原始碼的修改參考方向,實際上還是要改解壓縮的核心。


# 取得函數符號位址
手機連接電腦
adb shell
su
echo 0 > /proc/sys/kernel/kptr_restrict

cat /proc/kallsyms |grep load_module
c02b358c t load_module

cat /proc/kallsyms |grep check_version
c02b1fa8 t check_version.part.5

紀錄 load_module 跟 check_version.part.5 的位址

# 分析 Kernel
用 Debuger 打開 piggy
base address       0xC0008000
代碼段開始位址   0x1F9000     (每個核心不一樣 用 HEX 編輯器自己去看,不輸入也無所謂)

# load_module Patch
go to c02b358c (load_module)

往下找到這段操作代碼

符號是參考 module.o 添加上去,原本是不帶符號。
c02b3884         ldr        r2, = (Modulelayout)
c02b3888         mov        r0, r8
c02b388c         bl         sub_c02b1fa8      ; check_version.part.5
c02b3890         cmp        r0, #0x0
c02b3894         beq        loc_c02b3784      ; NOP

             loc_c02ab898:
c02b3898         cmn        r4, #0x1000
c02b389c         bhi        loc_c02b3f48
c02b38a0         ldr        r1, =aVermagic
c02b38a4         mov        r0, r5
c02b38a8         bl         sub_c02b1c10      ; get_modinfo
c02b38ac         tst        r7, #0x2
c02b38b0         mov        r6, r0
c02b38b4         bne        loc_c02b3784      ; NOP
c02b38b8         cmp        r0, #0x0
c02b38bc         beq        loc_c02b3784      ; NOP


0x2AB894 Patch: BA FF FF 0A   改為   00 F0 20 E3
0x2AB8B4 Patch: b2 ff ff 1a   改為   00 F0 20 E3
0x2AB8BC Patch: b0 ff ff 0a   改為   00 F0 20 E3

c02b38e8         str        r3, [fp, #-0xa0]
c02b38ec         beq        sub_c02ab58c+892
c02b38f0         ldr        r3, = (4.4.95+ SMP preempt mod_unload modversions ARMv7 p2v8)
c02b38f4         mov        r2, r6
c02b38f8         add        r1, r4, #0xc
c02b38fc         ldr        r0, = (version magic "%s" should be "%s")
c02b3900         bl         sub_c02f5f38      ; printk
c02b3904         b          loc_c02b3784      ; NOP

0x2AB904 Patch: 9e ff ff ea   改為   00 F0 20 E3

# check_version Patch
go to c02b1fa8 (check_version.part.5)
往下找到這段

c02b1ff0         mov        r0, r8         ; patch to  mov  r0, #0x1 (01 00 a0 e3)
c02b1ff4         ldm        sp, {r4, r5, r6, r7, r8, sb, fp, sp, pc}


0x2A9FF0 Patch: 08 00 a0 e1   改為   01 00 a0 e3

把要補釘的位置紀錄下來,Debuger 顯示的位址 剪掉基址 0xC0008000 就是檔案的篇移量。

用 HEX 編輯器打開 piggy 按照篇移量把補釘複寫進去就可以了。

打好補釘後壓縮 piggy
gzip -n -f -9 piggy
然後會得到一個 piggy.gz 的檔案

再用打開 piggy.gz,把 piggy.gz 的內容複製,按照「piggy.gz 的開始偏移量」複寫進 boot.img-zImage 就完成補釘了。

然後打包 boot.img 刷入。


以上是ARMv7 版本範例,armv8 大同小異。
三星機型 Binrary Patch 比較麻煩,保護太多不好改,用原始碼編譯比較方便。

取得 Kernel 的基址的方式
cat /proc/kallsyms > /sdcard/kallsyms

打開看 /sdcard/kallsyms
開頭的位址 - 代碼段開始偏移量 = 基址 (base address)。

arnv7 代碼段開始偏移量 通常是 0x1F9000
armv8 代碼段開始偏移量 通常是 0x1000


可以用 HEX 編輯器打開檢查
開頭有一段亂碼,接著一遍空白 00 byte,再下一大段亂碼就是代碼段 (code segment / text segment)。

Kernel.Binrary.Patch.txt

5.45 KB, 下載次數: 1, 下載積分: 碎鑽 -1 個

用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則