Konu Başlıkları Gizle
Bu mesajda, Kanadalı Foulab’in izlediği yolu adım adım toparlayıp, aynı yöntemi başka TP-Link modellerine de uygulayabilmemiz için bir özet paylaşıyorum.
Libcmm içindeki kritik fonksiyon:
Bu fonksiyonun yaptığı özetle şu:
OID string tablosundan:
Yani OID 2, IGD_DEV_INFO ile eşleşiyor. Rootfs içindeki XML şemada da bunu görüyoruz:
Foulab’ın “bnr_key muhtemelen X_TP_ProductID” demesinin sebebi bu.
IGD_DEV_INFO struct’ındaki bnr_key alanı, XML’deki X_TP_ProductID ile çok mantıklı şekilde örtüşüyor.
Dolayısıyla:
İlk bakışta insanın aklına şu gelebiliyor:
Ama fonksiyon bunu böyle kullanmıyor. Mantık şöyle:
Karakterlerin hex değerleri:
Her byte için:
Sonuçta elde edilen DES key:
Bu, Foulab’in paylaştığı anahtarla bire bir aynı.
Geri test de yapabiliyoruz:
Bu işlemi tersten yaptığınızda "4aa13401" string’ini geri alıyoruz, yani gerçekten bnr_key = 0x4aa13401.
Sadece:
yeterli.
Bu mantığa göre script’e eklenmiş hali:
Artık bu key’in nereden geldiği, nasıl üretildiği ve başka modellere nasıl aynısını uygulayabileceğini öğrenmiş olduk.
Techolay olarak bu işlem için Foulab'e C$100 bağış yaptık.
getBackNRestoreK Fonksiyonu Ne Yapıyor?
Libcmm içindeki kritik fonksiyon:
C++:
void getBackNRestoreK(byte *key)
{
byte bVar1;
int iVar2;
char *hex_;
byte xor[8];
byte dm_in[16];
char hex[16];
IGD_DEV_INFO_OBJ devInfo;
```
xor[4] = 0xf9;
xor[5] = 0x3e;
xor[6] = 0x2d;
xor[7] = 0xcf;
xor[0] = 0x74;
xor[1] = 0x8d;
xor[2] = 0xa5;
xor[3] = 0x0b;
memset(hex, 0, 16);
memcpy(dm_in, dm_in_getBackNRestoreK, 0xe);
// int dm_getObj(uint oid, ushort *in_buf, uint size, void *out_buf)
iVar2 = dm_getObj(2, dm_in, 0x988, &devInfo);
if (iVar2 == 0) {
memcpy(key, xor, 8);
hex_ = hex;
snprintf(hex_, 0x10, "%08x", devInfo.bnr_key);
do {
bVar1 = *hex_;
hex_ = (char *)((byte *)hex_ + 1);
*key = bVar1 ^ *key;
key = key + 1;
} while (hex_ != hex + 8);
} else {
cdbg_printf(8, "getBackNRestoreK", 0x136, "Get dev info for BNR key failed");
}
```
}
Bu fonksiyonun yaptığı özetle şu:
- 8 baytlık sabit bir “base key” dizisi tanımlıyor:
Kod:
xor = [0x74, 0x8d, 0xa5, 0x0b, 0xf9, 0x3e, 0x2d, 0xcf]
- dm_getObj(2, ...) çağrısıyla OID 2 için bir IGD_DEV_INFO_OBJ dolduruyor.
- IGD_DEV_INFO_OBJ içindeki 32-bit bir alanı (bnr_key) alıyor.
- bnr_key değerini "%08x" formatıyla ASCII hex string’e çeviriyor (8 karakter).
- Bu 8 karakteri, xor[] dizisindeki 8 baytla teker teker XOR’layarak final DES anahtarını üretiyor.
Kod:
final_key[i] = xor[i] ^ ascii_hex_bnr_key[i]
OID 2 → IGD_DEV_INFO ve XML Tarafı
OID string tablosundan:
Kod:
00199564 -> "IGD_DEV_INFO"
Yani OID 2, IGD_DEV_INFO ile eşleşiyor. Rootfs içindeki XML şemada da bunu görüyoruz:
XML:
<DeviceInfo t=o r=P s=IGD_DEV_INFO_OBJ>
...
<X_TP_ProductID t=u r=R d=0x4aa13401 nw=1 h=1 />
... </DeviceInfo>
Foulab’ın “bnr_key muhtemelen X_TP_ProductID” demesinin sebebi bu.
IGD_DEV_INFO struct’ındaki bnr_key alanı, XML’deki X_TP_ProductID ile çok mantıklı şekilde örtüşüyor.
Dolayısıyla:
Kod:
devInfo.bnr_key = 0x4aa13401;
Yanlış Yol: 0x4aa13401’i Doğrudan Key Sanmak
İlk bakışta insanın aklına şu gelebiliyor:
DES key = 0x4aa13401 veya bunun RAM’deki raw baytları.Ama fonksiyon bunu böyle kullanmıyor. Mantık şöyle:
- 0x4aa13401 → "%08x" → "4aa13401" (8 karakterlik ASCII string)
- Bu string’in her karakteri, xor[] içindeki ilgili bayt ile XOR’lanıyor.
- Sonuç: 8 baytlık DES anahtarı.
VC220-G3u İçin Hesabı Adım Adım Yapalım
Base XOR Key
Kod:
xor = [0x74, 0x8d, 0xa5, 0x0b, 0xf9, 0x3e, 0x2d, 0xcf]
bnr_key → ASCII
Kod:
bnr_key = 0x4aa13401
"%08x" → "4aa13401"
Karakterlerin hex değerleri:
Kod:
'4' = 0x34
'a' = 0x61
'a' = 0x61
'1' = 0x31
'3' = 0x33
'4' = 0x34
'0' = 0x30
'1' = 0x31
XOR İşlemi
Her byte için:
Kod:
1. 0x74 ^ 0x34 = 0x40
2. 0x8d ^ 0x61 = 0xec
3. 0xa5 ^ 0x61 = 0xc4
4. 0x0b ^ 0x31 = 0x3a
5. 0xf9 ^ 0x33 = 0xca
6. 0x3e ^ 0x34 = 0x0a
7. 0x2d ^ 0x30 = 0x1d
8. 0xcf ^ 0x31 = 0xfe
Sonuçta elde edilen DES key:
Python:
'vc220-g3u': b'\x40\xec\xc4\x3a\xca\x0a\x1d\xfe'
Bu, Foulab’in paylaştığı anahtarla bire bir aynı.
Geri test de yapabiliyoruz:
Kod:
final_key[i] ^ xor[i] = ascii("4aa13401")[i]
Bu işlemi tersten yaptığınızda "4aa13401" string’ini geri alıyoruz, yani gerçekten bnr_key = 0x4aa13401.
“Sadece libcmm + rootfs ile” Nasıl Bulunuyor?
Genel yöntem (başka TP-Link modelleri için de aynısı):- Libcmm içinde "getBackNRestoreK" string’ini veya fonksiyon referansını bul.
- Fonksiyonun içinde:
- 8 baytlık sabit bir diziyi tespit et (base xor key).
- dm_getObj(2, ...) çağrısını bul, son parametre IGD_DEV_INFO_OBJ pointer’ı.
- IGD_DEV_INFO_OBJ içinde bnr_key alanının offset’ini çıkart.
- Rootfs’teki TR-098/TR-181 XML şemalarında IGD_DEV_INFO_OBJ tanımına bak:
- X_TP_ProductID, X_TP_HardwareID, vs. alanları incele.
- Genelde d=0xXXXXXXXX şeklinde default ürün ID’si duruyor.
- Bu değeri al:
- bnr_key = 0xXXXXXXXX
- "%08x" → 8 karakterlik ASCII hex string.
- Base xor key ile bu 8 karakteri XOR’la → final DES key’i elde et.
Sadece:
libcmm.so + rootfs (XML şema)yeterli.
Python Script’te Kullanım
Bu mantığa göre script’e eklenmiş hali:
Python:
KEYS = {
'default': b'\x47\x8D\xA5\x0B\xF9\xE3\xD2\xCF',
'xz005-g6-un-v1': b'\x45\xEE\x92\x32\xCF\x5B\x1D\xFE',
'vc220-g3u': b'\x40\xec\xc4\x3a\xca\x0a\x1d\xfe',
}
Artık bu key’in nereden geldiği, nasıl üretildiği ve başka modellere nasıl aynısını uygulayabileceğini öğrenmiş olduk.
Techolay olarak bu işlem için Foulab'e C$100 bağış yaptık.