Reverse Engineering Dotnet Applications
https://starkeblog.com/reverse-engineering/dotnet/2024/04/18/reverse-engineering-dotnet-applications.html?s=35
@reverseengine
https://starkeblog.com/reverse-engineering/dotnet/2024/04/18/reverse-engineering-dotnet-applications.html?s=35
@reverseengine
❤4
Virtualization-based protection
بعضی محافظ ها کد اصلی رو تبدیل میکنن به یه بایت کد و یه مفسر/VM داخل برنامه میذارن که این بایت کد رو اجرا کنه این باعث میشه دیساسمبل مستقیم بی معنی یا سخت باشه
چطوری تشخیص بدیم یه باینری virtualized هست؟
وجود یه لوپ dispatcher بزرگ یک حلقه طولانی که بسته به مقدارِ یه متغیر شاخه رو انتخاب میکنه
خیلی از توابع یا بلاک ها به جای ASM معمولی فراخوانی هایی به یه مفسر/تابع dispatcher دارن
حجم زیادی از جدول بایت کد یا داده های عجیب داخل بخش .rdata/.data.
کنترل جریان عجیب و شاخه های نامعمول که توی دیساسمبل قابل فهم نیستن
سرعت اجرای توابع نسبت به کد نِیِتیو خیلی پایینتر چون مفسره
ابزارای مفید برای تشخیص و آنالیز:
IDA / Ghidra برای دیدن الگوها و dispatcher
x64dbg runtime
پیدا کردن جایی که dispatcher اجرا میشه
hexdump/strings/entropy برای پیدا کردن دادههای بایت کد
نوشتن اسکریپت ساده Python برای pattern matching توی باینری
ساخت یک VM ساده کد نمونه C
این کد یه برنامه خیلی ساده میسازه که یه رشته رو چک میکنه اما به جای اینکه مستقیم cmp کنه اول یه بایت کد ساده درست میکنه و بعد یه مفسر که اونو اجرا کنه این کار شبیهسازی یه virtualizer سطح پایینه و برای تمرین خیلی خوبه
نمونه کد کپی کنید و روی ماشین توسعه/VM خودتون کامپایل کنید
vm.c
کامپایل:
آنالیز استاتیک:
strings simple_vm
رو اجرا کنید و ببینید رشته ها کجا هستن
فایل رو توی IDA/Ghidra باز کنید دنبال تابع run_vm بگردید توی دیس اسمبل میبینید یه حلقه با switch/case و داده prog[] این همون dispatcher/binary bytecode هست
آنالیز داینامیک:
فایل رو با x64dbg باز کنید یک breakpoint بذارید روی run_vm یا روی آدرس آرایه prog
برنامه رو با ورودیهای مختلف اجرا کنید و ببینید چطور مسیر dispatcher تغییر میکنه
هدف اینه که بفهمید کجا بایتکدها هستن dispatcher چطوری براشون کار میکنه و منطق مقایسه کجاست
تشخیص VM:
dispatcher loop جدول بایت کد در دادهها فراخوانی مکرر مفسر
چجوری از استاتیک و داینامیک با هم استفاده میکنیم: استاتیک بایت کد رو پیدا میکنه داینامیک نشون میده runtime چه اتفاقی میوفته
devirtualization:
هدف اولی شناسایی dispatcher و داده بایت کد و مستند سازی منطق اجراست بعد میشه بایت کدها رو استخراج و معنی شون رو بازسازی کرد
Virtualization-based protection
Some protectors convert the source code into bytecode and embed an interpreter/VM inside the program to execute this bytecode, making direct disassembly pointless or difficult
How do we tell if a binary is virtualized?
A large dispatcher loop, a long loop that selects a branch depending on the value of a variable
Many functions or blocks have calls to an interpreter/dispatcher function instead of regular ASM
A large bytecode table or strange data in the .rdata/.data section.
Strange flow control and unusual branches that are not understandable in disassembly
Execution speed of functions is much lower than native code because it is interpreted
Useful tools for diagnostics and analysis:
IDA / Ghidra to see patterns and dispatcher
x64dbg runtime
@reverseengine
بعضی محافظ ها کد اصلی رو تبدیل میکنن به یه بایت کد و یه مفسر/VM داخل برنامه میذارن که این بایت کد رو اجرا کنه این باعث میشه دیساسمبل مستقیم بی معنی یا سخت باشه
چطوری تشخیص بدیم یه باینری virtualized هست؟
وجود یه لوپ dispatcher بزرگ یک حلقه طولانی که بسته به مقدارِ یه متغیر شاخه رو انتخاب میکنه
خیلی از توابع یا بلاک ها به جای ASM معمولی فراخوانی هایی به یه مفسر/تابع dispatcher دارن
حجم زیادی از جدول بایت کد یا داده های عجیب داخل بخش .rdata/.data.
کنترل جریان عجیب و شاخه های نامعمول که توی دیساسمبل قابل فهم نیستن
سرعت اجرای توابع نسبت به کد نِیِتیو خیلی پایینتر چون مفسره
ابزارای مفید برای تشخیص و آنالیز:
IDA / Ghidra برای دیدن الگوها و dispatcher
x64dbg runtime
پیدا کردن جایی که dispatcher اجرا میشه
hexdump/strings/entropy برای پیدا کردن دادههای بایت کد
نوشتن اسکریپت ساده Python برای pattern matching توی باینری
ساخت یک VM ساده کد نمونه C
این کد یه برنامه خیلی ساده میسازه که یه رشته رو چک میکنه اما به جای اینکه مستقیم cmp کنه اول یه بایت کد ساده درست میکنه و بعد یه مفسر که اونو اجرا کنه این کار شبیهسازی یه virtualizer سطح پایینه و برای تمرین خیلی خوبه
نمونه کد کپی کنید و روی ماشین توسعه/VM خودتون کامپایل کنید
vm.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
uint8_t prog[] = {
0x01, /* LOAD_INPUT */
0x10, /* expect length (16) or unused */
0x02, /* CMP_CONST */
'1','2','3','4',0, /* const "1234" + null */
0x03 /* HALT/END */
};
int run_vm(const char *input) {
int ip = 0;
while (ip < sizeof(prog)) {
uint8_t op = prog[ip++];
switch (op) {
case 0x01: // LOAD_INPUT -- store pointer (no-op for this demo)
// nothing to do; in real vm you'd load bytes to vm memory
break;
case 0x02: { // CMP_CONST
const char *c = (const char*)&prog[ip];
ip += 5; // length of constant in this toy example
if (strcmp(input, c) == 0) return 1;
break;
}
case 0x03:
return 0;
default:
return 0;
}
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) { printf("usage: %s <pass>\n", argv[0]); return 0; }
if (run_vm(argv[1])) printf("Access granted\n");
else printf("Access denied\n");
return 0;
}
کامپایل:
gcc simple_vm.c -o simple_vm
آنالیز استاتیک:
strings simple_vm
رو اجرا کنید و ببینید رشته ها کجا هستن
فایل رو توی IDA/Ghidra باز کنید دنبال تابع run_vm بگردید توی دیس اسمبل میبینید یه حلقه با switch/case و داده prog[] این همون dispatcher/binary bytecode هست
آنالیز داینامیک:
فایل رو با x64dbg باز کنید یک breakpoint بذارید روی run_vm یا روی آدرس آرایه prog
برنامه رو با ورودیهای مختلف اجرا کنید و ببینید چطور مسیر dispatcher تغییر میکنه
هدف اینه که بفهمید کجا بایتکدها هستن dispatcher چطوری براشون کار میکنه و منطق مقایسه کجاست
تشخیص VM:
dispatcher loop جدول بایت کد در دادهها فراخوانی مکرر مفسر
چجوری از استاتیک و داینامیک با هم استفاده میکنیم: استاتیک بایت کد رو پیدا میکنه داینامیک نشون میده runtime چه اتفاقی میوفته
devirtualization:
هدف اولی شناسایی dispatcher و داده بایت کد و مستند سازی منطق اجراست بعد میشه بایت کدها رو استخراج و معنی شون رو بازسازی کرد
Virtualization-based protection
Some protectors convert the source code into bytecode and embed an interpreter/VM inside the program to execute this bytecode, making direct disassembly pointless or difficult
How do we tell if a binary is virtualized?
A large dispatcher loop, a long loop that selects a branch depending on the value of a variable
Many functions or blocks have calls to an interpreter/dispatcher function instead of regular ASM
A large bytecode table or strange data in the .rdata/.data section.
Strange flow control and unusual branches that are not understandable in disassembly
Execution speed of functions is much lower than native code because it is interpreted
Useful tools for diagnostics and analysis:
IDA / Ghidra to see patterns and dispatcher
x64dbg runtime
@reverseengine
❤1
Find where dispatcher is executed
hexdump/strings/entropy to find bytecode data
Write a simple Python noscript for pattern matching in binary
Build a simple VM Sample C code
This code creates a very simple program that checks a string, but instead of cmp directly, it first creates a simple bytecode and then an interpreter to execute it. This is a low-level simulation of a virtualizer and is very good for practice
Copy the sample code and compile it on your development machine/VM
vm.c
Compile:
Static analysis:
Run strings simple_vm
and see where the strings are
Open the file in IDA/Ghidra and look for the function run_vm. In the disassembler you will see a loop with switch/case and data prog[] this is the dispatcher/binary bytecode
Dynamic analysis:
Open the file with x64dbg and set a breakpoint on run_vm or on the address of the array prog
Run the program with different inputs and see how the dispatcher path changes
The goal is to understand where the bytecodes are, how the dispatcher works for them and where the comparison logic is
VM detection:
dispatcher loop bytecode table in data repeated calls to the interpreter
How do we use static and dynamic together: static finds the bytecode dynamic shows the runtime what is happening It turns out
devirtualization:
The first goal is to identify the dispatcher and data bytecodes and document the execution logic. Then the bytecodes can be extracted and their meaning reconstructed.
@reverseengine
hexdump/strings/entropy to find bytecode data
Write a simple Python noscript for pattern matching in binary
Build a simple VM Sample C code
This code creates a very simple program that checks a string, but instead of cmp directly, it first creates a simple bytecode and then an interpreter to execute it. This is a low-level simulation of a virtualizer and is very good for practice
Copy the sample code and compile it on your development machine/VM
vm.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
uint8_t prog[] = {
0x01, /* LOAD_INPUT */
0x10, /* expect length (16) or unused */
0x02, /* CMP_CONST */
'1','2','3','4',0, /* const "1234" + null */
0x03 /* HALT/END */
};
int run_vm(const char *input) {
int ip = 0;
while (ip < sizeof(prog)) {
uint8_t op = prog[ip++];
switch (op) {
case 0x01: // LOAD_INPUT -- store pointer (no-op for this demo)
// nothing to do; in real vm you'd load bytes to vm memory
break
case 0x02: { // CMP_CONST
const char *c = (const char*)&prog[ip];
ip += 5; // length of constant in this toy example
if (strcmp(input, c) == 0) return 1;
break
}
case 0x03:
return 0;
default:
return 0;
}
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) { printf("usage: %s <pass>\n", argv[0]); return 0; }
if (run_vm(argv[1])) printf("Access granted\n");
else printf("Access denied\n");
return 0;
}
Compile:
gcc simple_vm.c -o simple_vm
Static analysis:
Run strings simple_vm
and see where the strings are
Open the file in IDA/Ghidra and look for the function run_vm. In the disassembler you will see a loop with switch/case and data prog[] this is the dispatcher/binary bytecode
Dynamic analysis:
Open the file with x64dbg and set a breakpoint on run_vm or on the address of the array prog
Run the program with different inputs and see how the dispatcher path changes
The goal is to understand where the bytecodes are, how the dispatcher works for them and where the comparison logic is
VM detection:
dispatcher loop bytecode table in data repeated calls to the interpreter
How do we use static and dynamic together: static finds the bytecode dynamic shows the runtime what is happening It turns out
devirtualization:
The first goal is to identify the dispatcher and data bytecodes and document the execution logic. Then the bytecodes can be extracted and their meaning reconstructed.
@reverseengine
❤4
Recon 2025 Breaking Obfuscated .NET Malware with Profiler Based Dynamic Binary Instrumentation
https://www.youtube.com/watch?v=jPDJ_Zo6jiY
@reverseengine
https://www.youtube.com/watch?v=jPDJ_Zo6jiY
@reverseengine
YouTube
Recon 2025 - Breaking Obfuscated .NET Malware with Profiler Based Dynamic Binary Instrumentation
Recon 2025 - Breaking Obfuscated .NET Malware with Profiler Based Dynamic Binary Instrumentation
Presenters: Lars Wallenborn, Tillmann Werner, Sebastian Walla, Steffen Haas
As malware authors increasingly adopt .NET for its ease of development and stability…
Presenters: Lars Wallenborn, Tillmann Werner, Sebastian Walla, Steffen Haas
As malware authors increasingly adopt .NET for its ease of development and stability…
❤4
❤4
Reverse Engineering Tools both Offensive and Defensive Operations can utilize
https://github.com/InfosecHouse/InfosecHouse/blob/main/re.md
@reverseengine
https://github.com/InfosecHouse/InfosecHouse/blob/main/re.md
@reverseengine
GitHub
InfosecHouse/re.md at main · InfosecHouse/InfosecHouse
Tools & Resources for Cyber Security Operations. Contribute to InfosecHouse/InfosecHouse development by creating an account on GitHub.
❤4
Deep Dive into a Modern Stealth Linux Kernel Rootkit
https://blog.kyntra.io/Singularity-A-final-boss-linux-kernel-rootkit
@reverseengine
https://blog.kyntra.io/Singularity-A-final-boss-linux-kernel-rootkit
@reverseengine
❤4
List of Awesome Reverse Engineering Resources
https://github.com/wtsxDev/reverse-engineering
@reverseengine
https://github.com/wtsxDev/reverse-engineering
@reverseengine
GitHub
GitHub - wtsxDev/reverse-engineering: List of awesome reverse engineering resources
List of awesome reverse engineering resources. Contribute to wtsxDev/reverse-engineering development by creating an account on GitHub.
❤3
Awesome Malware Development Resources
https://github.com/rootkit-io/awesome-malware-development
@reverseengine
https://github.com/rootkit-io/awesome-malware-development
@reverseengine
GitHub
GitHub - rootkit-io/awesome-malware-development: Organized list of my malware development resources
Organized list of my malware development resources - rootkit-io/awesome-malware-development
❤3
بخش سوم بافر اور فلو
تفاوت های مهم بین استک هیپ و خطاهای off by one رو بررسی میکنیم
توضیح stack overflow
استک جاییه که فریم تابع ها قرار میگیره و معمولا بافر های محلی اینجا ساخته میشن
استک overflow زمانی رخ میده که نوشته های بیش از اندازه به بافر محلی برسن و بخش هایی مثل saved rbp و saved return address رو بازنویسی کنه
در عمل این نوع باعث کرش سریع میشه و معمولا به صورت overwrite روی فریم جاری قابل مشاهده هست
توضیح کد استک
در این کد یک تابع بافر محلی داره و با strcpy مقدار وارد شده رو کپی میکنه
دیدن کرش و بررسی saved return address در gdb هست
کد استک فایل stack.c
#include <stdio.h>
#include <string.h>
void vuln(char *s) {
char buf[32];
printf("inside vuln\n");
strcpy(buf, s);
printf("buf says %s\n", buf);
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("usage stack input\n");
return 1;
}
vuln(argv[1]);
printf("returned normally\n");
return 0;
}
دستورات اجرا و دیباگ مربوط به استک
این دستورات رو اجرا کنید تا کرش و فریم رو ببینید
gcc -g stack.c -o stack
gdb --args ./stack $(python3 -c "print('A'*80)")
داخل gdb
break vuln
run
info frame
x/40gx $rbp
backtrace
Part Three Buffer Overflow
We examine important differences between stack, heap, and off‑by‑one errors
Explanation stack overflow
The stack is where function frames are placed and local buffers are usually allocated
A stack overflow occurs when writes exceed a local buffer and overwrite areas like saved rbp and the saved return address
In practice this type causes a fast crash and is usually visible as an overwrite on the current frame
Explanation stack code
In this code a function has a local buffer and uses strcpy to copy the supplied input
You will see the crash and inspect the saved return address in gdb
Stack source file stack.c
#include <stdio.h>
#include <string.h>
void vuln(char *s) {
char buf[32];
printf("inside vuln\n");
strcpy(buf, s);
printf("buf says %s\n", buf);
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("usage stack input\n");
return 1;
}
vuln(argv[1]);
printf("returned normally\n");
return 0;
}
Commands to build and debug the stack
Run these commands to see the crash and inspect the frame
gcc -g stack.c -o stack
gdb --args ./stack $(python3 -c "print('A'*80)")
Inside gdb
break vuln
run
info frame
x/40gx $rbp
backtrace
@reverseengine
❤3
BlackSuit Ransomware Actors Breached Corporate Environment
https://cybersecuritynews.com/blacksuit-ransomware-vmware-esxi
@reverseengine
https://cybersecuritynews.com/blacksuit-ransomware-vmware-esxi
@reverseengine
Cyber Security News
BlackSuit Ransomware Actors Breached Corporate Environment, Including 60+ VMware ESXi Hosts
The BlackSuit ransomware group, tracked as Ignoble Scorpius by cybersecurity experts, devastated a prominent manufacturer's operations.
❤3
این کنفرانس در زمینه ی مهندسی معکوس و توسعه اکسپلویت هست
This conference is about reverse engineering and exploit development.
https://www.youtube.com/@reconmtl/videos
@reverseengine
This conference is about reverse engineering and exploit development.
https://www.youtube.com/@reconmtl/videos
@reverseengine
Youtube
- YouTube
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.
❤3