Image

Malware giriş.

Malware

BlackNullSec Path : MEMORY ROADMAP

🚀 Memory aşaması = malware dünyasına giriş kapısı

şöyle düşün:

Pointer = silah
Memory = savaş alanı
Process Memory = düşman bölgesi


🔎 RAM’i böyle düşün:


RAM = lineer bir byte dizisi

[0x1000] → 41
[0x1001] → 42
[0x1002] → 43
[0x1003] → 44


Bu ne demek?

👉 Her adres 1 byte
👉 Her adres = index gibi


DEĞİŞKENLER GERÇEKTE NE?

Sen bunu böyle görüyorsun:
int x = 10;
Ama sistem şöyle görüyor:
Adres: 0x1000
Değer: 0A 00 00 00 (little endian)


⚠️ KRİTİK NOKTA

👉 int = 4 byte
👉 RAM = byte bazlı
Yani:
10 sayısı = 4 parçaya bölünüyor


POINTER NE YAPIYOR?

int x = 10;
int *p = &x;
Memory’de:
[0x1000] → 0A 00 00 00 (x)
[0x2000] → 00 10 00 00 (p → x’in adresi)
👉 pointer = adres tutar
Önemli:)
Pointer = memory içindeki başka bir noktaya giden yol


POINTER ARİTMETİĞİ GERÇEKTE NE YAPIYOR?

int *p = 0x1000;
p + 1;
Bu ne olur?
👉 0x1004

Çünkü: pointer + 1 = sizeof(type) kadar ilerler

FORMÜl: (Address + offset) = (BasePointer + n × sizeof(type))


💣 NEDEN BU KRİTİK?

PE header parsing
shellcode
encryption
signature scan

👉 hepsi byte seviyesinde yapılır


💣MEMORY OPERATIONS

memcpy → veri taşıma (payload copy)
memset → temizleme / obfuscation
memcmp → karşılaştırma


memcpy

Şunu yapar: *(dest + i) = *(src + i);

👉 pointer arithmetic + byte copy memcpy nerede kullanılır?
shellcode inject ederken
payload decrypt ederken
config load ederken
👉 Yani:
memcpy = malware core tool
Örnek:)
char src[4] = {1,2,3,4};
char dest[4];
memcpy(dest, src, 4);
Memory’de ne olur?:)

BAŞLANGIÇ:)
src:
[1][2][3][4]
dest:
[?][?][?][?]
👉 memcpy sonrası:)
dest:
[1][2][3][4]
⚠️ KRİTİK NOKTA)
👉 bu byte copy’dir
👉 type önemli değil

Örnek:)
int x = 0x12345678;
int y;
memcpy(&y, &x, 4);
y kaç olur?
👉 0x12345678
Memory’de nasıl görünür?
y:
78 56 34 12

🧠 NEDEN BÖYLE?
memcpy(&y, &x, 4) → byte byte kopya
Sistem → little endian
Bu yüzden en düşük byte öne gelir
👉 memcpy:
“adres taşımaz”
“değerin byte’larını taşır”

🔴 SORUN
“Biri düz (0x12345678), diğeri neden ters (78 56 34 12)?”
👉 Çünkü:
Register / sayı gösterimi = “insan okuma formatı”
Memory = “byte byte saklama formatı”
Ve sistem:
Little Endian kullanıyor

🔥 1. “DÜZ” GÖRÜNEN NE?
int x = 0x12345678;
Bu bir sayıdır. CPU bunu şöyle yorumlar:
0x12345678
👉 Bu sadece anlam (value)
🔴 2. MEMORY NASIL TUTAR?
Memory byte bazlıdır:
78 56 34 12

👉 Çünkü:

Little endian = en düşük byte önce yazılır
🧠 PARÇALAYALIM
0x12345678

Byte’lara ayır:

12 | 34 | 56 | 78

🔴 Big Endian (mantıksal sıralama)

12 34 56 78

🔥 Little Endian (gerçek memory)

78 56 34 12

🧠 ZİHİN MODELİ

Value (mantık):
0x12345678
Memory (gerçek):
[78][56][34][12]

💥 MALWARE / RE GERÇEĞİ

Bu yüzden:
debugger’da hex dump ters görünür
PE header okurken offset’ler karışır
signature scan yaparken byte sırası önemlidir
👉 Eğer endian’ı anlamazsan:
yanlış analiz yaparsın


🔴 VERİLEN

int x = 0x11223344;
unsigned char *p = (unsigned char*)&x;
printf("%02X\n", p[2]);

🔴 1. Memory görünümü (Little Endian)

0x11223344

Memory’de:

44 33 22 11

✅ DOĞRU CEVAP

👉 p[2] = 22

🔥 KRİTİK KURAL

index = byte offset

🔴 2. Index mantığı


🧠 ZİHİN MODELİ

Adres      Değer
0x1000     44  ← p[0]
0x1001     33  ← p[1]
0x1002     22  ← p[2]
0x1003     11  ← p[3]


🔥 (NOT AL)

Not: Memory asla ters değildir, pointer her zaman ileri gider; ters görünen şey CPU’nun multi-byte veriyi yorumlama şeklidir. Little endian:Memory ters değil,yorumlama ters.

🔥 (NOT AL)

Not: Little endian = memory’ye nasıl yazıldığıdır
Pointer = memory’yi nasıl okuduğundur

Sayı düz yazılır, memory’ye yazılırken little endian’a göre parçalanır

🔴 ADIM ADIM

1. SEN KODDA YAZIYORSUN
int x = 0xA1B2C3D4;
👉 Bu sadece mantıksal değer (value)<
A1 B2 C3 D4

🔴 2. CPU BUNU MEMORY’YE KOYUYOR

Sistem:
👉 Little Endian

🔥 NE YAPIYOR?

D4 C3 B2 A1

👉 yani:
en küçük byte (D4) → ilk adres
en büyük byte (A1) → son adres

💣 KRİTİK CÜMLE

Kod “tersine çevrilmez”
👉 memory’ye yazılırken byte sırası düzenlenir
Not: unsigned char x[8] = {
0x4D, 0x5A, 0x90, 0x00,
0x03, 0x00, 0x00, 0x00
};
printf("%x\n", *(int*)(x + 4));


HANGİ BYTE’LAR OKUNUR?

(x + 4)
👉 Başlangıç: index 4
Memory:

[0] 4D
[1] 5A
[2] 90
[3] 00
[4] 03  ← başlangıç
[5] 00
[6] 00
[7] 00

✔ Okunan:

03 00 00 00

SONUÇ NE?


👉 RAM düz
👉 CPU little endian yorumluyor
Little endian → düşük byte önce
03 00 00 00 → 0x00000003
👉 Doğru sonuç:
0x3

🔴 DOĞRU YORUM


Memory: 03 00 00 00
Değer: 0x00000003
👉 printf çıktısı = CPU’nun yorumudur



Örnek

int *p = (int*)0x1000;
Soru:
(char*)p + 3
👉 kaç byte ilerler?
👉 sonuç adres ne olur?
int *p = (int*)0x1000;
(char*)p + 3

ADIM ADIM ANALİZ

1. Başlangıç


p = 0x1000

👉 int* → normalde 4 byte zıplar

2. CAST NE YAPTI?



(char*)p
👉 Pointer tipi değişti:
❌ artık int* değil
✔ char* oldu
🔥 KRİTİK SONUÇ
👉 Artık pointer arithmetic:

sizeof(char) = 1

3. HESAP


(char*)p + 3

👉
3 × 1 = 3 byte
👉
0x1000 + 3 = 0x1003
✅ DOĞRU SONUÇ

👉 3 byte ilerler
👉 adres = 0x1003

🧪 MINI DRILL (BUNU ÇÖZ)


struct Test {
char a; // 0
int b; // 4
};
unsigned char mem[8] = {
0x11, 0x00, 0x00, 0x00,
0x78, 0x56, 0x34, 0x12
};

👉 SORU:



*(int*)(mem + 4) = ?


🔍 VERİ

struct Test {
char a; // offset 0
int b; // offset 4
};
unsigned char mem[8] = {
0x11, 0x00, 0x00, 0x00,
0x78, 0x56, 0x34, 0x12
};

mem + 4 NE YAPAR?

Senin dediğin doğru:

👉 mem = unsigned char*
👉 +4 = 4 byte ilerler
[4] → 0x78 ← başlangıç

AMA SONRA NE OLUYOR?


*(int*)(mem + 4)

👉 Bu şu demek:

"Buradan başlayarak 4 byte oku ve int olarak yorumla"

OKUNAN BYTE'LAR


78 56 34 12

LITTLE ENDIAN YORUMLAMA



Memory: 78 56 34 12
Değer: 0x12345678
✅ SONUÇ
*(int*)(mem + 4) = 0x12345678

⚔️ PE BAĞLANTISI (EN ÖNEMLİ NOKTA)


Bu yaptığın şeyin aynısı:

dos->e_lfanew = *(int*)(base + 0x3C);


👉 Yani:
base + 0x3C → başlangıç
int → 4 byte oku
little endian → değeri oluştur

🌟 Sonraki Yazı: İndex_vs_Offset

← Önceki Sonraki →

⚠️ Kritik Uyarı

Bu teknikler yalnızca eğitim amaçlıdır. Gerçek sistemlere uygulanması yasadışı olabilir. Asla gerçek ortamlarda test etme.

BlackNullSec
“Windows Belleğiyle Konuşan Kodlar”