ReverseEngineering – Telegram
ReverseEngineering
1.24K subscribers
40 photos
10 videos
55 files
666 links
Download Telegram
Control-flow flattening و Junk Code

توضیح:
کد ساده رو طوری مینویسن یا تبدیل میکنن که ترتیب منطقیش معلوم نباشه با جدول پریدن‌ ها و کلی شاخه بی‌ ربط یا کلی کد بی‌ فایده junk میزنن تا تشخیص الگوریتم سخت شه


یادتونه یه if ساده چقدر خوندنش راحته؟ بعضی‌ها اون if رو میکوبن توی یه جدول پریدن و چند تا case اضافه میکنن دیگه شبیه لابیرنت میشه همین کار باعث میشه خوندن جریان برنامه سخت شه

مثال:
در CFG میبینید به‌ جای چند شاخه ساده کلی بلاک کوچک و پرش بین جدول‌ هاست این یعنی control-flow flattening یا اضافه کردن کد بی‌ ربط

دیتکشن

گراف کنترل جریان خیلی تودرتو و شاخه‌ های زیاد

توابع خیلی طولانی پر از jumps و switch-like tables

کدهایی که ظاهرا کاری نمیکنن ولی اجرا‌ میشن


میتیگیشن

آنالیزور: ترکیب static و dynamic analysis یعنی هم disasm ببینید هم اجرا کن تا بفهمید کد واقعی کدیه که در runtime فعال میشه

توسعه‌دهنده: مستند سازی و unit test تا اگر مجبور به obfuscation شدید حداقل تیمتون بتونه نگهش داره


Control-flow flattening and Junk Code

Explanation:
They write or transform simple code in such a way that its logical order is not clear, with jump tables and a lot of irrelevant branches or a lot of useless code, making it difficult to understand the algorithm

Remember how easy a simple if is to read? Some people throw that if in a table, jump and add a few cases, and it becomes like a labyrinth, which makes it difficult to read the program flow.

Example:
In CFG, instead of a few simple branches, you see a whole bunch of small blocks and jumps between tables. This means control-flow flattening or adding irrelevant code.

Detection

The control flow graph is very nested and has many branches.

Very long functions full of jumps and switch-like tables.

Code that doesn't seem to do anything but is executed.

Mitigation

Analyzer: A combination of static and dynamic analysis, meaning you can see both disasm and execute it to understand that the real code is the code that will be activated at runtime.

Developer: Documentation and unit testing so that if you have to obfuscate, at least your team can maintain it.


@reverseengine
3
Roadmap Malware Analysis

C

C++

Reverse engineering for beginners book and other corses

Assembly

Windows Internals

Win32 Api

Python

Malware analysis professional course

Zero2automated course

Sans for 610

practical malware analysis book

Malware analysis cookbook book

Mastering malware analysis packtpub book


این رودمپ رو خیلی وقت پیش خودم نوشتم برای دوستانی که میخان تحلیل بدافزار انجام بدن استفاده کنن

I wrote this roadmap a long time ago for my friends who want to do malware analysis to use

@reverseengine
4
UPX
و نمونه‌ های پیچیده‌ تر

فایل اصلی فشرده یا رمز میشه و Loader موقع اجرا محتوا رو آنپک میکنه  پس static analysis اغلب بی‌ فایده‌ ست تا وقتی که unpack شدن انجام بشه


یه فایل ممکنه کوچیک باشه ولی وقتی اجرا میکنی ناگهان یه قسمت بزرگ از کد تو حافظه ظاهر میشه  یعنی packed بوده مثل اینکه یه جعبه بسته رو باز کنی و داخلش یه چیز دیگه باشه

مثال:
تو header یا با نگاه کردن به اندازه امضا میتونید بفهمید packed هست در اجرای برنامه میبینید بخش ههای جدیدی توی حافظه ساخته میشه  علامت unpacking

دیتکشن

امضا های packer شناخته‌ شده توی header

افزایش ناگهانی بخش‌های اجرایی در حافظه بعد از لانچ

رفتار loader در runtime که حافظه رو مینویسه و بعد jump به بخش جدید میزنه


میتیگیشن

اجرا در sandbox/VM با مانیتورینگ کامل (فایل شبکه پروسس) تا رفتار after-unpack دیده بشه

برای سازمان‌ ها: امضای فایل‌ ها و بررسی integrity قبل از اجرا و quarantine کردن فایل‌ های مشکوک



UPX and more complex examples

The original file is compressed or encrypted and the Loader unpacks the content at runtime, so static analysis is often useless until unpacking is done

A file may be small, but when you run it, a large chunk of code suddenly appears in memory, meaning it was packed, like opening a closed box and there's something else inside

Example:
You can tell it's packed in the header or by looking at the size of the signature. When running the program, you'll see new sections being created in memory, a sign of unpacking

Detection

Known packer signatures in the header

Sudden increase in executable sections in memory after launch

Loader behavior at runtime that writes memory and then jumps to a new section

Mitigation

Run in a sandbox/VM with full monitoring (process network file) to see after-unpack behavior

For organizations: file signing and integrity checking before execution and quarantining suspicious files

@reverseengine
4
تابع‌هایی که از stack frame استفاده نمیکنن (Leaf بدون Prologue)

پس این قسمت کلیدی هست


مثال C:

int add5(int x) {
return x + 5;
}


اسمبلی بهینه کامپایلر (O2):

add5:
lea eax, [rdi + 5]
ret


چرا اینجا push rbp و mov rbp, rsp نداریم؟

چون:

تابع هیچ متغیر محلی نداره

تابع تابع دیگری رو فرانمیخونه (leaf)

مقدار برگشتی(return address) فقط در رجیستر‌ها محاسبه میشه

نتیجه: کامپایلر stack frame نمیسازه


Functions that do not use stack frame (Leaf without Prologue)

So this is the key part

C example:

int add5(int x) {
return x + 5;
}


Compiler optimized assembly (O2):

add5:
lea eax, [rdi + 5]
ret


Why don't we have push rbp and mov rbp, rsp here?

Because:

The function has no local variables

The function does not call another function (leaf)

The return value (return address) is calculated only in registers

Result: The compiler does not create a stack frame

@reverseengine
4
نشونه ها داخل دیس‌ اسمبلی

push rbp + mov rbp, rsp
فریم ساخته شده


sub rsp, x متغیر محلی وجود داره


دسترسی به [rbp - offset]
استفاده از متغیر محلی روی استک

call
معمولا Non-leaf (به جز Tail-call)


نبودن RBP و کار فقط با RSP
خروجی کامپایلر بهینه‌ سازی شده است


Symbols inside the disassembly

push rbp + mov rbp, rsp Frame created


sub rsp, x Local variable exists


Access to [rbp - offset]
Use local variable on stack


Call is usually Non-leaf (except Tail-call)


No RBP and only works with RSP
Compiler output is optimized


@reverseengine
5
Virtualization-based Obfuscation Devirtualization و Kernel RE
(فقط نرم‌افزار)

Virtualization-based Obfuscation VMProtect / Themida


یه لایه مجازی‌ ساز داخل باینری میذارن: کد اصلی تبدیل میشه به دستورالعمل‌ های مخصوص VM و یه انجین در زمان اجرا اونا رو اجرا میکنه سخت میشه بفهمید اصل منطق چیه

مثال:
نمونه open-source که با ابزار obfuscator ساده بسته‌ بندی شده رو باز کنید و ببینید بخش dispatcher چطور بین بلاک‌ ها سوئیچ میکنه فقط ببینید و ساختار جدول پرش رو تحلیل کنید نه حذف حفاظ

دیتکشن (چی باید نگاه کنید)

وجود یک حلقه dispatcher که با جدول‌ ایندکس‌ ها بلاک‌ ها رو اجرا میکنه

الگو های ثابت decode/dispatch در چند تا تابع

کاهش شدید خوانایی pseudocode اما افزایش پیچیدگی CFG


میتیگیشن (مدافع/توسعه‌دهنده)

برای توسعه‌دهندگان: از Obfuscation‌ فقط وقتی لازم باشه استفاده کنید و مستندات داخلی رو نگه‌ دارید

آنالیزور/مدافع: ترکیب آنالیز ایستا و دینامیک لاگ‌ گیری runtime و trace گرفتن از dispatcher کمک میکنه تا بفهمید VM چه دستورات منطقی‌ ای اجرا میکنه




Virtualization-based Obfuscation Devirtualization and Kernel RE
(software only)

Virtualization-based Obfuscation VMProtect / Themida

Puts a virtualization layer inside the binary: the original code is converted to VM-specific instructions and an engine executes them at runtime. It is difficult to understand the logic behind it.

Example:
Open the open-source example packaged with a simple obfuscator tool and see how the dispatcher section switches between blocks. Just look and analyze the jump table structure, not remove the protection.

Detection (what to look for)

Presence of a dispatcher loop that executes blocks with index tables.

Constant decode/dispatch patterns in several functions.

Severely reduces pseudocode readability but increases CFG complexity.

Mitigation (Defender/Developer)

For developers: Use Obfuscation only when necessary and keep internal documentation.

Analyzer/Defender: Analysis combination Static and dynamic runtime logging and dispatcher tracing help you understand what logical commands the VM is executing.

@reverseengine
5
این پروژه یک وایت بورد در IDA در اختیارتون میزاره که میتونید داخلش هر چیزی که خواستید رو طراحی کنید

This project provides you with a whiteboard in IDA where you can design anything you want

https://github.com/idkhidden/DrawIDA

@reverseengine
6
Devirtualization
روش‌های دفاع/تحلیلی


وقتی با VM-based obfuscation روبه‌رو میشید باید بفهمید چه الگویی برای برگردوندن pseudocode استفاده میکنن راه‌ حل‌ ها معمولا ترکیبی از آنالیز ایستا برای شناسایی و آنالیز دینامیک برای تقلید اجرای VM هستن

مثال:
trace
گرفتن از اجرای برنامه و استخراج sequence ای از دستورات dispatche
مثل opcode های VM و دسته‌ بندی‌ شون بدون اینکه بخواید قفل‌‌ ها رو بشکنید فقط ساختار دستورها رو ببینید

دیتکشن

الگوهای تکراری در dispatcher که به opcodeهای مشخص اشاره میکنن

مقادیر ثابت جدول‌های ترجمه که در runtime خونده و استفاده میشن


میتیگیشن

محقق: مستندسازی دقیق از رفتار runtime و نگهداری traces برای تحلیل‌های بعدی

توسعه‌دهنده: اگر از VM استفاده میکنی لاگ‌های داخلی برای تیم خودت نگه دار تا در troubleshooting بهت کمک کنه


Devirtualization
Defense/Analysis Methods

When faced with VM-based obfuscation, you need to understand what pattern they are using to return pseudocode. Solutions are usually a combination of static analysis to identify and dynamic analysis to mimic VM execution

Example:
Trace
Taking a program execution and extracting a sequence of dispatcher instructions

Like VM opcodes and their categories without trying to break the locks, just see the instruction structure

Detection

Repeated patterns in dispatcher that point to specific opcodes

Constant values of translation tables that are read and used at runtime

Mitigation

Researcher: Accurately document runtime behavior and maintain traces for later analysis

Developer: If you use VM, keep internal logs for your team to help you troubleshoot


@reverseengine
1
بخش هفتم بافر اورفلو


یافتن آفست دقیق بین ابتدای بافر و saved return address و دیدن قبل و بعد strcpy با الگوی غیر تکراری

فایل تولید الگو توضیح
این فایل یک الگوی غیر تکراری تولید میکنه تا با مقدار برگشتی که روی استک میبینیم بتونیم آفست رو حساب کنیم

فایل file4_pattern.py

#!/usr/bin/env python3
# simple cyclic pattern generator
import sys
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
nums = "abcdefghijklmnopqrstuvwxyz"
digits = "0123456789"
def pattern(n):
out = []
for a in alpha:
for b in nums:
for c in digits:
out.append(a+b+c)
if len("".join(out)) >= n:
return "".join(out)[:n]
return "".join(out)[:n]

if name == "main":
n = int(sys.argv[1]) if len(sys.argv)>1 else 200
print(pattern(n))


دستورات اجرا برای یافتن آفست و دیدن قبل و بعد strcpy
تولید الگو و اجرای فایل با الگو به عنوان ورودی

python3 file4_pattern.py 200 > pat.tx

t
gcc -g file4.c -o fil

e4
gdb --args ./file4 $(cat pat.txt)


# در gdb

break crash
run
x/32x $rbp-32 # strcpy قبل از
next # strcpy اجرای کامل
x/32x $rbp-32 # strcpy بعد از
continue # تا کرش اگر لازمه

پیدا کردن مقدار overwrite شده توضیح
بعد از کرش یا بعد از دیدن در gdb مقدار 8 بایتی که در محل return address افتاده رو بردارید و به صورت رشته hex بخونید

مثال دستور داخل gdb برای دیدن 8 بایت در محل return address

x/gx $rbp+8

توضیح فایل محاسبه آفست
این فایل یک تابع ساده برای پیدا کردن موقعیت یک رشته کوچیک داخل الگوی تولید شده میسازه

فایل file4_find_offset.py

#!/usr/bin/env python3
import sys
from file4_pattern import pattern

def find(sub, total=200):
p = pattern(total)
idx = p.find(sub)
return idx

if name == "main":
# ورودی sub به صورت بایت hex یا رشته باید به درستی فرمت شود
sub = sys.argv[1]
# اگر hex داده شد تبدیل کن
if sub.startswith("0x"):
raw = bytes.fromhex(sub[2:])
sub = raw.decode('latin-1')
print(find(sub, int(sys.argv[2]) if len(sys.argv)>2 else 200))



Part 7 Buffer Overflow

Finding the exact offset between the beginning of the buffer and the saved return address and seeing before and after strcpy with a non-repeating pattern

Pattern generation file Explanation
This file generates a non-repeating pattern so that we can calculate the offset with the return value we see on the stack

File file4_patte run.py

#!/usr/bin/env python3
# simple cyclic pattern generator
import sys
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
nums = "abcdefghijklmnopqrstuvwxyz"
digits = "0123456789"
def pattern(n):
out = []
for a in alpha:
for b in nums:
for c in digits:
out.append(a+b+c)
if len("".join(out)) >= n:
return "".join(out)[:n]
return "".join(out)[:n]

if name == "main":
n = int(sys.argv[1]) if len(sys.argv)>1 else 200
print(pattern(n))


Execution commands to find offset and see before and after strcpy
Generate pattern and execute file with pattern as input

python3 file4_pattern.py 200 >pat.txt
gcc -g file4.
c -o file4
gdb --args ./file4 $(cat pat.txt)
# in gdb

break crash

run

x/32x $rbp-32 # strcpy before

next # strcpy complete execution

x/32x $rbp-32 # strcpy after

continue # until crash if necessary

Finding overwritten value Explanation
After crash or after seeing in gdb, take the 8 bytes that are in the return address and write them as Read hex string

Example of gdb command to see 8 bytes at

return address


x/gx $rbp+8


File denoscription Calculate offset

This file creates a simple function to find the position of a small string within the generated pattern

File file4_find_offset.py

#!/usr/bin/env python3
import sys
from file4_pattern import pattern

def find(sub, total=200):
p = pattern(total)
idx = p.find(sub)
return idx

if name == "main":
# Sub input as hex bytes or string must be formatted properly
sub = sys.argv[1]
# Convert if given hex
if sub.startswith("0x"):
raw = bytes.fromhex(sub[2:])
sub = raw.decode('latin-1')
print(find(sub, int(sys.argv[2]) if len(sys.argv)>2 else 200))
@reverseengine
1
Kernel Reverse Engineering Syscalls Drivers Kernel Debugging


تحلیل کد سطح کرنل یعنی کار با درایورها و syscall ها ابزار ها روش ها متفاوت و خطرناکن بنابر این باید فقط برای درک و دفاع انجام بشه نه سو استفاده

مثال:
با یک درایور نمونه open-source کار کن: build کن داخل VM نصب کنید و با WinDbg یا kgdb دیباگ کنید تا ببینید syscall چطور پارامترها رو میگذرونه تمرکز روی فهم API و کنترل‌ فلو نه ایجاد exploit

دیتکشن

درایور های unsigned یا درایور هایی که اقدام به رجیستر کردن syscall های جدید میکنن

رفتار های غیر عادی مثل تغییر مستقیم ساختار های کرنل یا نصب hook های غیر معمول


میتیگیشن

محدود کردن نصب درایورهای ناشناس (signature enforcement) استفاده از HVCI/Kernel Patch Protection

مانیتورینگ تغییرات کرنل و هشدار به‌ موقع مشاهده ماژول/درایور جدید یا نوشتن در مناطق حساس

Kernel Reverse Engineering Syscalls Drivers Kernel Debugging

Kernel-level code analysis means working with drivers and syscalls. Tools and methods are different and dangerous, so it should only be done for understanding and defense, not for exploitation.

Example:
Work with an open-source sample driver: build it, install it inside a VM, and debug it with WinDbg or kgdb to see how the syscall passes parameters. Focus on understanding the API and control flow, not creating exploits.

Detection

Unsigned drivers or drivers that attempt to register new syscalls.

Anomalies such as directly modifying kernel structures or installing unusual hooks.

Mitigation

Restricting installation of unknown drivers (signature enforcement). Use HVCI/Kernel Patch Protection.

Monitoring kernel changes and alerting when new modules/drivers are detected or written to sensitive areas

@reverseengine
1
ARM64 Reversing and Exploitation Part 2 Use After Free | 8kSec Blogs


https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free

@reverseengine
1
ساخت یک باینری نیتیو (Win32) شبیه‌ سازی‌ شده که مکانیزم‌ های واقعی حفاظت آنتی‌ دیباگ ساده چک یکپارچگی تولید سریال بر اساس اسم  داخل داشته باشه تا بدون ریسک قانونی بتونید تمرین RE و عملیات کرک‌ سازی رو انجام بدید

ویژگی‌ها:

GUI
ساده با فیلدهای Name و Serial و دکمه Activate & Play

Anti-Debug: فراخوانی
IsDebuggerPresent() قبل از فعال‌سازی

Integrity (شبیه‌سازی):
بررسی ساده مسیر exe قابل ارتقا به checksum واقعی

الگوریتم سریال: تابع gen_expected_serial که روی نام کاربر s = s*31 + ch انجام میده و بعد سه گروه 16‌بیتی با XOR/شیفت میسازه خروجی در قالب AAAA-BBBB-CCCC

پیام موفق/ناموفق با MessageBoxA.


هشدار اخلاقی/قانونی: این کد فقط برای تمرین روی باینری‌ ایه که خودتون ساختید کرک و انتشار کرک نرم‌ افزارهای تجاری غیرقانونیه


کد کامل فایل hotspot_sim.c

کد رو دقیقا در یک فایل به اسم hotspot_sim.c ذخیره کنید

// hotspot_sim.c
یک برنامه شبیه‌ سازی‌ شده برای تمرین RE

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

// شناساگر کنترل‌ها
#define IDC_NAME  1001
#define IDC_SERIAL 1002
#define IDC_BUTTON 1003

// یه تابع ساده برای ساختن سریال مورد انتظار بر اساس اسم کاربر
// فرمت خروجی: AAAA-BBBB-CCCC (اعداد هگز چهار رقمی)
void gen_expected_serial(const char *name, char *out, size_t outlen)
{
    unsigned long s = 0;
    // جمع مقادیر کاراکترها رو می‌گیریم
    for (size_t i = 0; i < strlen(name); ++i) {
        s = s * 31 + (unsigned char)name[i]; // یه ضرب و جمع ساده
    }
    // میایم سه گروه 16 بیتی می‌سازیم
    unsigned g1 = (unsigned)((s ^ 0xA5A5A5A5) & 0xFFFF);
    unsigned g2 = (unsigned)(((s >> 3) ^ 0x5A5A5A5A) & 0xFFFF);
    unsigned g3 = (unsigned)(((s << 7) ^ 0x3C3C3C3C) & 0xFFFF);
    // قالب‌بندی نهایی
    _snprintf_s(out, outlen, _TRUNCATE, "%04X-%04X-%04X", g1, g2, g3);
}

// تابعی که سریال ورودی رو با سریال تولیدشده مقایسه می‌کنه
int verify_serial(const char *name, const char *serial)
{
    char expected[64];
    gen_expected_serial(name, expected, sizeof(expected));
    // اینجا مقایسهٔ ساده میکنیم (حساس به حروف)
    if (_stricmp(expected, serial) == 0) return 1;
    return 0;
}

// تابعی که integrity ساده رو شبیه‌سازی می‌کنه
// اینجا فقط چک می‌کنیم که exe path طول مشخصی داشته باشه (نمونه‌ست)
int integrity_ok()
{
    char path[MAX_PATH];
    if (GetModuleFileNameA(NULL, path, MAX_PATH) == 0) return 0;
    size_t L = strlen(path);
    // شبیه‌سازی: اگه طول مسیر خیلی کوتاه باشه یا خیلی بلند باشه خطا بدیم
    if (L < 5) return 0;
    return 1;
}

// پنجره اصلی و پردازش پیام‌ها
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
    {
        // یک لیبل و یک فیلد برای نام
        CreateWindowA("static", "Name:", WS_VISIBLE | WS_CHILD, 10, 10, 50, 20, hWnd, NULL, NULL, NULL);
        CreateWindowA("edit", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
                      70, 10, 240, 22, hWnd, (HMENU)IDC_NAME, NULL, NULL);

        // لیبل و فیلد سریال
        CreateWindowA("static", "Serial:", WS_VISIBLE | WS_CHILD, 10, 40, 50, 20, hWnd, NULL, NULL, NULL);
        CreateWindowA("edit", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
                      70, 40, 240, 22, hWnd, (HMENU)IDC_SERIAL, NULL, NULL);

        // دکمه Activate
        CreateWindowA("button", "Activate & Play", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                      110, 80, 120, 30, hWnd, (HMENU)IDC_BUTTON, NULL, NULL);
        break;
    }
    case WM_COMMAND:
    {
        if (LOWORD(wParam) == IDC_BUTTON)
        {
            // اگه دیباگر باشه لغو می‌کنیم
            if (IsDebuggerPresent()) {
                MessageBoxA(hWnd, "Activation failed: debugger detected.", "Error", MB_OK | MB_ICONERROR);
                break;
            }

            // integrity ساده
            if (!integrity_ok()) {
                MessageBoxA(hWnd, "Activation failed: integrity check failed.", "Error", MB_OK | MB_ICONERROR);
1
                break;
            }

// گرفتن متن از کنترل‌ ها
            char name[128] = {0};
            char serial[128] = {0};
            HWND hName = GetDlgItem(hWnd, IDC_NAME);
            HWND hSerial = GetDlgItem(hWnd, IDC_SERIAL);
            GetWindowTextA(hName, name, sizeof(name));
            GetWindowTextA(hSerial, serial, sizeof(serial));

            // پاک کردن فضای خالی ابتدای/انتهای رشته
            if (strlen(name) == 0) {
                MessageBoxA(hWnd, "Please enter your name first.", "Info", MB_OK | MB_ICONINFORMATION);
                break;
            }
            if (strlen(serial) == 0) {
                MessageBoxA(hWnd, "Please enter serial.", "Info", MB_OK | MB_ICONINFORMATION);
                break;
            }

            // بررسی سریال
            if (verify_serial(name, serial)) {
                MessageBoxA(hWnd, "Activation successful! Playing...", "OK", MB_OK | MB_ICONINFORMATION);
            } else {
                MessageBoxA(hWnd, "Invalid serial!", "Error", MB_OK | MB_ICONERROR);
            }
        }
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProcA(hWnd, msg, wParam, lParam);
    }
    return 0;
}

// نقطهٔ ورود برنامه ویندوزی
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // ساخت کلاس پنجره
    WNDCLASSA wc = {0};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "HotspotSimClass";
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);

    if (!RegisterClassA(&wc)) return -1;

    // ساخت پنجره
    HWND hWnd = CreateWindowA("HotspotSimClass", "Hotspot Player (Simulated - Native)",
                              WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
                              CW_USEDEFAULT, CW_USEDEFAULT, 340, 160, NULL, NULL, hInstance, NULL);
    if (!hWnd) return -1;

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    // لوپ پیام ساده
    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }

    return (int)msg.wParam;
}



Build a simulated native (Win32) binary that has real anti-debug protection mechanisms, simple integrity check, serial generation based on the name inside, so you can practice RE and cracking operations without legal risk

Features:

Simple GUI
with Name and Serial fields and Activate & Play button

Anti-Debug: Call
IsDebuggerPresent() before activation

Integrity (simulation):
Simple check of exe path, upgradeable to real checksum

Serial algorithm: gen_expected_serial function that does s = s*31 + ch on the username and then creates three 16-bit groups with XOR/shift. Output in the format AAAA-BBBB-CCCC

Success/Failure message with MessageBoxA.

Ethical/Legal Warning: This code is for practice only on a binary that you have created yourself. Cracking and distributing commercial software is illegal

Full code of the hotspot_sim.c file

Save the code exactly in a file named hotspot_sim.c

// hotspot_sim.c
A simulated program for practicing RE
Simple and vernacular explanations and comments

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

// Control identifiers
#define IDC_NAME 1001
#define IDC_SERIAL 1002
#define IDC_BUTTON 1003

// A simple function to generate the expected serial based on the user name
// Output format: AAAA-BBBB-CCCC (four-digit hex numbers)
void gen_expected_serial(const char *name, char *out, size_t outlen)
{
unsigned long s = 0;
// We take the sum of the character values
for (size_t i = 0; i < strlen(name); ++i) {
s = s * 31 + (unsigned char)name[i]; // A simple multiplication and addition
}
// Let's create three 16-bit groups
unsigned g1 = (unsigned)((s ^ 0xA5A5A5A5) & 0xFFFF);
unsigned g2 = (unsigned)(((s >> 3) ^ 0x5A5A5A5A) & 0xFFFF);
unsigned g3 = (unsigned)(((s << 7) ^ 0x3C3C3C3C) & 0xFFFF);
// Final formatting
_snprintf_s(out, outlen, _TRUNCATE, "%04X-%04X-%04X", g1, g2, g3);
}
1