PatchWork Dosyasının Reverse Çözümü
Dosya Bilgileri
File olarak uygulamayı incelediğimizde dosya bilgileri aşağıda ki gibidir :
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=bd54832bd17c6e91e740ff54e618b08e31ed3621, for GNU/Linux 3.2.0, not stripped
Radare2 İle Patch
Çalıştırdığımızda ise ;
Trampolines are quite fun!; I love to jump!
You should try jumping too! It'll sure be more fun than reversing the flag manually.
Result sonucunu alıyoruz.
Burada bayrak dissamble edilerek kodu incelenebilir.
Radare2 ile aa
, s main
komutları takibinde VV
komutu ile grafiksel olarak inceleyebiliriz.Daha sonra ise q
ile çıkış yapabiliriz.
Görselde görüldüğü üzere main() fonksiyonunun çalışma prensibi Graph olarak yer almaktadır.Buradan yola çıkarak code_0x116C adresine yönlendirildiği görülmektedir.
0 ile 0 karşılaştırması yapıldığından dolayı Give_Flag() fonksiyonuna tam olarak geçiş sağlanamamaktadır.
Burada ise 0x0000116c
adresine gittiğimizde JUMP
olarak 0x0000116a
adresine atlamamız gerekmektedir.
wa jmp 0x0000116c@0x0000116a
komutu ile atlama işlemi gerçekleştirdikten sonra tekrardan dosyayı çalıştırdığımızda ise ;
bayrağa ulaşıyoruz :
Trampolines are quite fun!; I love to jump!
You should try jumping too! It'll sure be more fun than reversing the flag manually.
PCTF{JuMp_uP_4nd_g3t_d0Wn}
Give_Flag() fonksiyonu incelenerekte çözüme ulaşılabilir.
Give_Flag() Fonksiyonunun İncelenmesi
void give_flag(void)
{
undefined8 *puVar1; // İşaretçi tanımlanır
undefined8 local_38; // 8 byte'lık değişkenler tanımlanır
undefined8 local_30;
undefined8 local_28;
undefined2 local_20;
undefined local_1e;
undefined8 *local_18; // İşaretçiler tanımlanır
undefined8 *local_10;
// Değişkenlere sabit değerler atanır
local_38 = 0x9dc59acb96a493a0;
local_30 = 0xb4be84afa0c5afc0;
local_28 = 0xa780b4afc483b7af;
local_20 = 0xcdbe;
local_1e = 0;
local_10 = &local_38; // İşaretçi local_38'e ayarlanır
// İlk döngü: local_10 işaretçisi NULL karakteri ('\0') bulana kadar döner
while (*(char *)local_10 != '\0') {
puVar1 = (undefined8 *)((long)local_10 + 1); // İşaretçiyi bir sonraki karaktere kaydır
*(char *)local_10 = *(char *)local_10 + -0x50; // Karakterin ASCII değerini 80 (0x50) azalt
local_10 = puVar1; // İşaretçiyi güncelle
}
puts((char *)&local_38); // Değiştirilmiş dizeyi yazdır
local_18 = &local_38; // İşaretçiyi tekrar local_38'e ayarla
// İkinci döngü: local_18 işaretçisi NULL karakteri ('\0') bulana kadar döner
while (*(char *)local_18 != '\0') {
puVar1 = (undefined8 *)((long)local_18 + 1); // İşaretçiyi bir sonraki karaktere kaydır
*(char *)local_18 = *(char *)local_18 + 'P'; // Karakterin ASCII değerine 'P' ekleyin
local_18 = puVar1; // İşaretçiyi güncelle
}
return; // İşlev sona erer
}
Bu Kod bloğunu daha okunabilir hale getirmek için ve C olarak derlenerek çalıştırabileceğimiz bir program haline getirerek çözüme ulaşabiliriz.
#include <stdio.h>
void give_flag() {
unsigned long long local_38 = 0x9dc59acb96a493a0ULL;
unsigned long long local_30 = 0xb4be84afa0c5afc0ULL;
unsigned long long local_28 = 0xa780b4afc483b7afULL;
unsigned short local_20 = 0xcdbe;
unsigned short local_1e = 0;
unsigned long long local_10[] = {local_38, local_30, local_28, local_20, local_1e};
char result[41]; // 40 karakter uzunluğunda sonuç + 1
for (int i = 0; i < 5; i++) {
unsigned long long value = local_10[i];
unsigned char byteArray[8];
for (int j = 0; j < 8; j++) {
byteArray[j] = (unsigned char)(value & 0xFFULL);
value >>= 8;
}
for (int j = 0; j < 8; j++) {
byteArray[j] -= 0x50;
}
for (int j = 0; j < 8; j++) {
result[i * 8 + j] = byteArray[j];
}
}
result[40] = '\0'; // Sonuç dizesini sonlandır
printf("%s\n", result);
}
int main() {
give_flag();
return 0;
}
Sonuç :
Bu Kod bloğunu açıklayabilmeye çalışalım ;
İlgili büyük tamsayılar unsigned long long
veri türünde değişkenlere atanır. Bu tamsayılar programın ana mantığını temsil eder.
unsigned short
veri türünde iki tane daha değişken tanımlanır: local_20
ve local_1e
. Bu iki değişken, 2 baytlık
(16 bit) tamsayıları temsil eder.
unsigned long long
veri türündeki tamsayılar bir dizi olan local_10
içine yerleştirilir.
Bir sonuç dizesi olan result tanımlanır. Bu dize sonucun depolanacağı yerdir. 41
karakter uzunluğundadır çünkü sonuna bir null
karakteri eklemek için bir karakter daha gereklidir.
Burada ki result[41]
değiştirilebilir tabiki fakat böyle çözüme ulaştığımızda dolayı değiştirmiyorum.
Bir döngü başlatılır. Bu döngü, local_10
dizisindeki her büyük tamsayıyı işler.
Her büyük tamsayı, 8 bayta
dönüştürülür ve bu baytlar byteArray
dizisine atanır. Bu işlem, büyük tamsayının her baytını ayırır.
Ardından, her bayttan 0x50 (80)
çıkarılır. Bu, baytları ASCII
karakterlere dönüştürmek için kullanılır.
Elde edilen ASCII karakterler, sonucu oluşturmak için result dizisine eklenir.
Son olarak, result dizisinin sonuna null karakter ('\0')
eklenir. Bu, C dizilerinin sonunu belirtir.
Sonuç, printf kullanılarak ekrana yazdırılır.
main işlevi tanımlanır ve give_flag işlemini çağırır. Programın ana giriş noktasıdır.
Bu program, büyük tamsayıları baytlara dönüştürerek ve baytları ASCII karakterlere dönüştürerek sonucu oluşturur ve sonucu ekrana yazdırır.
Sonuç, "PCTF{JuMp_uP_4nd_g3t_d0Wn}"
olacaktır.
Programın Orijinal Kod Bloğu
Kod bloğu ise aşağıda ki gibidir.Soru çözümü sonrasında yayınlanmıştır.
#include <stdio.h>
#define HIDE_LETTER(a) (a) + 0x50
#define UNHIDE_STRING(str) do { char * ptr = str ; while (*ptr) *ptr++ -= 0x50; } while(0)
#define HIDE_STRING(str) do {char * ptr = str ; while (*ptr) *ptr++ += 0x50;} while(0)
int main()
{
int jump = 0;
printf("Trampolines are quite fun!; I love to jump! \n");
printf("You should try jumping too! It\'ll sure be more fun than reversing the flag manually.\n");
if (jump) {
give_flag();
}
return 0;
}
int give_flag()
{
// store the "secret password" as mangled byte array in binary
char flag[] = { HIDE_LETTER('P') , HIDE_LETTER('C') , HIDE_LETTER('T') , HIDE_LETTER('F') , HIDE_LETTER('{')
, HIDE_LETTER('J') , HIDE_LETTER('u') , HIDE_LETTER('M') , HIDE_LETTER('p') , HIDE_LETTER('_'),
HIDE_LETTER('u') ,HIDE_LETTER('P') ,HIDE_LETTER('_') ,HIDE_LETTER('4') ,HIDE_LETTER('n'), HIDE_LETTER('d'),
HIDE_LETTER('_'), HIDE_LETTER('g'), HIDE_LETTER('3'), HIDE_LETTER('t'), HIDE_LETTER('_'), HIDE_LETTER('d'),
HIDE_LETTER('0'),HIDE_LETTER('W'),HIDE_LETTER('n'), HIDE_LETTER('}'),'\0' };
UNHIDE_STRING(flag); // unmangle the string in-place
printf("%s\n", flag);
HIDE_STRING(flag); //mangle back
}