O software sabe que dia é hoje. Mas você pode mudar o que ele acha que é "expirado".
Trial de 2024. Você está em 2026. A matemática não te favorece.
O software compara time(NULL) com um timestamp hardcoded.
Duas abordagens: mudar o que o binário considera como data de expiração, ou mudar o que ele considera como "expirado".
time(NULL) retorna o timestamp atual; a expiração é um valor fixo calculado a partir de constantes de data.timegm(). Os campos tm_year, tm_mon, tm_mday aparecem como constantes no disassembly de get_expiry().time() com uma implementação que retorna um timestamp falso — invisível ao binário original.Abre o disassembly de get_expiry().
Os valores EXPIRY_YEAR - 1900, EXPIRY_MONTH - 1 e EXPIRY_DAY são atribuídos como constantes ao struct tm.
Onde você vê 0x7c (124 = 2024 - 1900) no disassembly?
objdump -d ./challenge | grep -A15 ""
0x7c (decimal 124 = 2024 - 1900) sendo carregada no struct tm:401196: c7 45 d0 7c 00 00 00 mov DWORD PTR [rbp-0x30], 0x7c ; tm_year = 124 40119d: c7 45 d4 00 00 00 00 mov DWORD PTR [rbp-0x2c], 0x0 ; tm_mon = 0 4011a4: c7 45 d8 01 00 00 00 mov DWORD PTR [rbp-0x28], 0x1 ; tm_mday = 1
2099 - 1900 = 199 = 0xC7. Substitui o byte 7c por c7 no offset correto.r2 -w ./challenge s 0x401199 # 3 bytes após o início da instrução = início da constante wx c7 00 00 00 # 199 em little-endian q
if (now >= expiry) — em asm isso é um jge (opcode 7d). Trocando por jl (7c), o bloco de "expirado" nunca é atingido.objdump -d ./challenge | grep "jge" # anota o endereço r2 -w ./challenge s <endereço do jge> wx 7c q
// fake_time.c #include <time.h> time_t time(time_t *t) { time_t fake = 1000000000; // 2001 — antes da expiração if (t) *t = fake; return fake; }
gcc -shared -fPIC -o fake_time.so fake_time.c LD_PRELOAD=./fake_time.so ./challenge
LD_PRELOAD injeta a implementação falsa de time() em runtime. O programa acredita que está em 2001.2024-01-01 UTC → Unix timestamp: 1704067200 2026-06-02 UTC → Unix timestamp: 1748822400 1748822400 >= 1704067200 → true → expirado patcheando para 2099-01-01: timestamp: 4070908800 1748822400 < 4070908800 → false → válido ✓
| Abordagem | Modifica o binário | Persiste | Rastro forense |
|---|---|---|---|
| patchear tm_year | Sim — 1 byte em .text | Sim | Constante alterada |
| inverter jge→jl | Sim — 1 byte em .text | Sim | Opcode alterado |
| LD_PRELOAD | Não | Não (sessão) | Nenhum no binário |
| faketime | Não | Não | Nenhum no binário |
Se o software enviasse o timestamp pro servidor e o servidor validasse a licença remotamente, qual dessas abordagens ainda funcionaria? Qual exigiria algo diferente — como interceptação de tráfego de rede?