Ir para conteúdo

Os Melhores

Conteúdo popular

Mostrando conteúdo com a maior reputação em 06/05/2026 em Posts

  1. Fala pessoal blz, estou descompilando o sistema de painéis do WYD Global e pra facilitar minha vida criei esse script .idc que faz a analise completa e extrai diversas informações digamos interessantes do cliente, o que facilita bem a vida. Como fiz para o WYD trabalha só com o exes compilados em MSVC, mas pode facilmente ser ajustado para trabalhar com outros compiladores e tbm outros exes. No próprio script tem a descrição das opções de configuração. Para usarem, salvem como XXXXX.idc, basta carregar o exe no IDA Shift+F2 importar o script ou colar o conteúdo no editor de script e rodar. A analise pode demorar a depender do tamanho do exe analisado e do seu pc tbm. Seguem alguns prints. bom é isso... /* * ============================================================================ * Vtable Analyzer Pro v5.3 - By Guilherme Candiotto * MSVC RTTI / vtable harvester for IDA Free 9.x and IDA Pro 7.x+ * ============================================================================ * * WHAT IT DOES * ------------ * Detects C++ classes in MSVC binaries via RTTI (CompleteObjectLocator), * reconstructs the inheritance hierarchy (including multi-inheritance via * secondary vtables), names virtual methods, applies __thiscall + this * typing for Hex-Rays, infers sizeof, detects singletons, annotates * virtual call sites, and emits a C++ header with the recovered classes. * * HOW TO USE * ---------- * File > Script file... -> select this .idc * * Outputs in <OUTPUT_DIR>: * vtables_analysis.json structured class data (parents, methods, ...) * vtables_analysis.log plain-text run log * vtables_overrides.json override relationships (child slot -> parent) * wyd_classes.h C++ header with reconstructed classes * * Re-run with Alt+F5 (configurable via REGISTER_HOTKEY). * * REQUIREMENTS * ------------ * IDA Free 9.x or IDA Pro >= 7.x. * MSVC binary with RTTI enabled (CompleteObjectLocator present). * Tested on x86; x64 supported via BRUTE_FORCE_X64_RVA path. * * CONFIG * ------ * See #defines below. Each one is documented at its declaration. * * License: MIT. Use freely; attribution appreciated. * ============================================================================ */ #include <idc.idc> // ---------------------- CONFIG ---------------------- // Pasta onde gravar os arquivos de saida. // "" = mesma pasta do .idb (recomendado). // "D:/path" = caminho absoluto. Use / ou \\ no Windows. #define OUTPUT_DIR "" #define OUTPUT_JSON_NAME "vtables_analysis.json" // structured class data (parents, methods, sizeof, ...) #define OUTPUT_LOG_NAME "vtables_analysis.log" // plain-text run log (progress + warnings) #define OUTPUT_OVERRIDES_NAME "vtables_overrides.json" // override map: child slot -> parent function #define OUTPUT_HEADER_NAME "wyd_classes.h" // C++ header with reconstructed classes (importable in IDA Local Types) #define DRY_RUN 0 // 1 = preview only (no IDB modification, no file writes) #define CREATE_STRUCTS 1 // 1 = create opaque <Class>_t struct in IDA (vptr at offset 0) #define RENAME_OVERRIDES 0 // 1 = rename even functions with existing custom names (e.g. from PDB); 0 = preserve them #define SCAN_DATA_TOO 1 // 1 = scan .data segment too (some binaries have vtables there, not just .rdata) #define STRING_FIRST_SCAN 1 // 1 = scan via RTTI strings (.?AV/.?AU), reconstruct TD/COL/vtable from xrefs #define POINTER_FIRST_SCAN 1 // 1 = sequential DWORD scan in .rdata looking for TD->COL pointer pattern (classic mode) #define PROPAGATE_OVERRIDES 1 // 1 = final pass detecting overrides (child slot != parent func) vs inherited methods #define BRUTE_FORCE_X64_RVA 1 // so executa em x64; inerte em x86 #define BRUTE_FORCE_X86 1 // varredura simetrica para x86 (sig=0) #define APPLY_THISCALL_TYPES 1 // aplica __thiscall(_t *this) nos vmethods #define DETECT_OBJECT_SIZES 1 // tenta deduzir sizeof via operator new #define DETECT_SINGLETONS 1 // marca globais que recebem instancias #define ANNOTATE_VCALLS 1 // comenta call [reg+N] com possibilidades #define EMIT_CPP_HEADER 1 // emite wyd_classes.h #define VCALL_MAX_METHODS 4 // max metodos listados por slot #define MAX_VTABLE_METHODS 2048 // safety cap: vtables larger than this are rejected (likely false positives) #define MIN_VTABLE_METHODS 1 // minimum slots to consider a vtable valid // v5.2 ---- #define CLEAR_OUTPUT_ON_START 1 // limpa Output do IDA no inicio #define REGISTER_HOTKEY 1 // Alt+F5 re-roda o script #define HOTKEY_COMBO "Alt-F5" // hotkey to re-run the script (IDA hotkey syntax: "Mod-Key") #define PROGRESS_EVERY 4096 // emite msg() a cada N iteracoes // v5.3: filtro de classes framework (MFC/STL/ATL/etc) #define EXCLUDE_FRAMEWORK_CLASSES 1 // 1 = pula MFC, STL, ATL, Gdiplus... // v5.3: detectores melhorados #define SIZE_INFER_FROM_BODY 1 // estima sizeof pelo max [this+N] no ctor #define SIZE_BODY_SCAN_LIMIT 80 // max instrucoes a olhar no body do ctor #define SINGLETON_AGGRESSIVE 1 // tenta padroes adicionais alem do basico // v5.3: limite de varredura para string-first scan (evita travar em // binarios de servidor com .data gigante (>100MB de tabelas de jogo). // 0 = sem limite. Default: 50MB. #define STRING_SCAN_MAX_SEG_SIZE 0x3200000 // 50MB // Cores BGR usadas pra colorir cada tipo de item no Disassembly View do IDA. // Formato: 0xBBGGRR. Mude pra 0 pra desabilitar coloracao especifica. #define COLOR_VTABLE_SLOT 0xFFE8E0 #define COLOR_VFUNC 0xE0FFE0 #define COLOR_PURE 0xC0C0C0 #define COLOR_DTOR 0xC0C0FF #define COLOR_CTOR 0xC0FFFF #define COLOR_RTTI_COL 0xE0E0FF #define COLOR_TYPE_DESC 0xFFE0FF #define COLOR_OVERRIDE 0xE0FFFF // Nomes de arrays internos do IDB (mantem cache entre runs do script). // Mude o sufixo (_v5_/_v4_) se quiser invalidar o cache forcando re-scan. #define ARR_VT_SEEN "vap_v4_vt_seen" #define ARR_TD2VT "vap_v4_td2vt" #define ARR_VT2TD "vap_v4_vt2td" #define ARR_VT2COL "vap_v4_vt2col" #define ARR_VT2COUNT "vap_v4_vt2count" #define ARR_VT2NAME "vap_v4_vt2name" #define ARR_VT2PARENTS "vap_v4_vt2parents" #define ARR_VT_LIST "vap_v4_vt_list" #define ARR_VT2OFFSET "vap_v5_vt2offset" // COL.offset (0=primary) #define ARR_VT2SIZE "vap_v5_vt2size" #define ARR_VT2SINGLETON "vap_v5_vt2singleton" #define ARR_SLOT_METHODS "vap_v5_slot_methods" #define ARR_HDR_EMITTED "vap_v5_hdr_emitted" #define ARR_TOPO_VISITED "vap_v5_topo_visited" #define ARR_TOPO_ORDER "vap_v5_topo_order" #define ARR_TOPO_COUNT "vap_v5_topo_count" // ---------------------- GLOBAIS ---------------------- // FIX IDC 9.x: variaveis globais usam "extern", nao "static" (que eh // reservado pra funcoes). Senao o parser cuspia "Missing brace". extern g_ptr_size; extern g_is_64; extern g_imagebase; extern g_log_handle; extern g_json_handle; extern g_overrides_handle; extern g_json_first; extern g_overrides_first; extern g_vt_list_count; extern g_stat_classes; extern g_stat_methods; extern g_stat_renamed; extern g_stat_ctors; extern g_stat_dtors; extern g_stat_pures; extern g_stat_overrides; extern g_stat_inherited; extern g_stat_brute; extern g_stat_thiscall; extern g_stat_sizes; extern g_stat_singletons; extern g_stat_vcalls; extern g_stat_header_classes; extern g_stat_renamed_inherited; extern g_stat_errors; extern g_purecall_csv; extern g_stat_filtered; // ========================================================================= // user_cancelled() - cooperative cancel hook (IDC stub) // ========================================================================= // IDC 9.x removed the wait_box / user_cancelled API; only IDAPython still // exposes it (idaapi.user_cancelled / ida_kernwin.user_cancelled). // // This stub always returns 0, so the if (user_cancelled()) checks scattered // across the heavy scan loops below are dead code - a long run cannot be // aborted gracefully from IDC (you have to kill the IDA process). // // TO ENABLE REAL CANCEL SUPPORT (IDAPython port): // 1. Wrap this script as an IDAPython plugin (.py instead of .idc). // 2. Replace this stub with: // import ida_kernwin // def user_cancelled(): // return ida_kernwin.user_cancelled() // 3. Bracket the main() entry with: // ida_kernwin.show_wait_box("HIDECANCEL\nVtable Analyzer: running...") // try: // main() // finally: // ida_kernwin.hide_wait_box() // 4. The 10 existing `if (user_cancelled()) return;` calls in this script // will then start working as cooperative cancel points. // // Until then, this stub keeps the IDC source compatible and side-effect-free. // ========================================================================= static user_cancelled() { return 0; } // ========================================================================= // LOG // ========================================================================= static log_line(level, line) { auto stamp = "[" + level + "] " + line; msg("%s\n", stamp); if (g_log_handle != 0) fprintf(g_log_handle, "%s\n", stamp); } static log_info(line) { log_line("INFO", line); } static log_warn(line) { log_line("WARN", line); } static log_error(line) { log_line("ERR ", line); g_stat_errors = g_stat_errors + 1; } // ========================================================================= // PATH HELPERS // ========================================================================= static find_last_char(s, c) { if (s == 0 || s == "") return -1; auto i; auto last = -1; auto n = strlen(s); for (i = 0; i < n; i = i + 1) { if (substr(s, i, i + 1) == c) last = i; } return last; } static dirname_of(path) { if (path == 0 || path == "") return ""; auto p1 = find_last_char(path, "\\"); auto p2 = find_last_char(path, "/"); auto pos = (p1 > p2) ? p1 : p2; if (pos == -1) return ""; return substr(path, 0, pos); } static normalize_path(p) { if (p == 0 || p == "") return ""; auto out = ""; auto i; auto n = strlen(p); for (i = 0; i < n; i = i + 1) { auto c = substr(p, i, i + 1); if (c == "\\") out = out + "/"; else out = out + c; } return out; } static path_join(dir, name) { if (dir == "" || dir == 0) return name; auto d = normalize_path(dir); auto last = substr(d, strlen(d) - 1, strlen(d)); if (last == "/") return d + name; return d + "/" + name; } static resolve_output_dir() { if (OUTPUT_DIR != "" && OUTPUT_DIR != 0) return normalize_path(OUTPUT_DIR); auto idb = get_idb_path(); auto d = dirname_of(idb); if (d == "" || d == 0) return "."; return normalize_path(d); } static safe_fopen(path, mode) { auto h = fopen(path, mode); if (h == 0) { msg("[ERR ] FOPEN FALHOU: '%s' (modo '%s')\n", path, mode); msg(" -> Verifique se a pasta existe e tem permissao de escrita.\n"); msg(" -> Ajuste OUTPUT_DIR no topo do script se necessario.\n"); return 0; } msg("[INFO] arquivo aberto OK: %s\n", path); return h; } // ========================================================================= // HELPERS BASICOS // ========================================================================= static read_ptr(ea) { return g_is_64 ? get_qword(ea) : get_dword(ea); } static rva_to_ea(rva) { return g_imagebase + rva; } static seg_is_executable(ea) { if (!is_loaded(ea)) return 0; return (get_segm_attr(ea, SEGATTR_PERM) & SEGPERM_EXEC) != 0; } static seg_name_of(ea) { if (!is_loaded(ea)) return ""; return get_segm_name(ea); } static is_valid_code_ptr(ea) { if (ea == BADADDR || ea == 0) return 0; if (!is_loaded(ea)) return 0; return seg_is_executable(ea); } static is_valid_data_ptr(ea) { if (ea == BADADDR || ea == 0) return 0; return is_loaded(ea); } static starts_with(s, prefix) { if (s == 0 || prefix == 0) return 0; if (strlen(s) < strlen(prefix)) return 0; return substr(s, 0, strlen(prefix)) == prefix; } static ends_with(s, suffix) { if (s == 0 || suffix == 0) return 0; auto sl = strlen(s); auto pl = strlen(suffix); if (sl < pl) return 0; return substr(s, sl - pl, sl) == suffix; } static sanitize_name(s) { if (s == 0 || s == "") return "anon"; auto out = ""; auto i; auto n = strlen(s); for (i = 0; i < n; i = i + 1) { auto c = substr(s, i, i + 1); if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || (c >= "0" && c <= "9") || c == "_") { out = out + c; } else if (c == ":" || c == "<" || c == ">" || c == "," || c == " " || c == "*" || c == "&" || c == "(" || c == ")" || c == "[" || c == "]" || c == "-" || c == "." || c == "+" || c == "/" || c == "\\" || c == "$" || c == "@" || c == "?") { out = out + "_"; } } if (out == "") out = "anon"; return out; } // ========================================================================= // JSON ESCAPING // ========================================================================= static json_escape(s) { if (s == 0 || s == "") return ""; auto out = ""; auto i; auto n = strlen(s); for (i = 0; i < n; i = i + 1) { auto c = substr(s, i, i + 1); if (c == "\"") out = out + "\\\""; else if (c == "\\") out = out + "\\\\"; else if (c == "\n") out = out + "\\n"; else if (c == "\r") out = out + "\\r"; else if (c == "\t") out = out + "\\t"; else out = out + c; } return out; } // ========================================================================= // PURECALL ADDRESS LOOKUP (cache de enderecos conhecidos via imports) // ========================================================================= static csv_contains_long(csv, val) { if (csv == "" || csv == 0) return 0; auto buf = ""; auto i; auto n = strlen(csv); for (i = 0; i <= n; i = i + 1) { auto c = (i < n) ? substr(csv, i, i + 1) : ","; if (c == ",") { if (buf != "" && atol(buf) == val) return 1; buf = ""; } else { buf = buf + c; } } return 0; } static csv_append_long(csv, val) { if (csv == "") return ltoa(val, 10); return csv + "," + ltoa(val, 10); } static init_purecall_addresses() { g_purecall_csv = ""; auto names_buf = "__purecall|_purecall|purecall|__cxa_pure_virtual|_cxa_pure_virtual"; auto buf = ""; auto i; auto n = strlen(names_buf); for (i = 0; i <= n; i = i + 1) { auto c = (i < n) ? substr(names_buf, i, i + 1) : "|"; if (c == "|") { if (buf != "") { auto ea = get_name_ea_simple(buf); if (ea != BADADDR && !csv_contains_long(g_purecall_csv, ea)) { g_purecall_csv = csv_append_long(g_purecall_csv, ea); } } buf = ""; } else { buf = buf + c; } } } static is_known_purecall_addr(ea) { return csv_contains_long(g_purecall_csv, ea); } // ========================================================================= // PARSER MANUAL DO NOME MANGLED (com tratamento de templates) // // .?AV<Classe>@<NS_inner>@<NS_outer>@@ // .?AU<Struct>@<NS_inner>@<NS_outer>@@ // // Resultado em C++ pseudo: NS_outer::NS_inner::Classe // Templates "?$Nome@..." viram "tpl_Nome" para nao quebrar o sanitize. // ========================================================================= static cleanup_template_segment(seg) { if (!starts_with(seg, "?$")) return seg; auto rest = substr(seg, 2, strlen(seg)); auto pos = strstr(rest, "@"); auto name; if (pos != -1) name = substr(rest, 0, pos); else name = rest; if (name == "") name = "tpl"; return "tpl_" + name; } static manual_parse_rtti_name(mangled) { if (mangled == 0 || mangled == "") return ""; if (strlen(mangled) < 6) return ""; auto prefix = substr(mangled, 0, 4); if (prefix != ".?AV" && prefix != ".?AU") return ""; auto rest = substr(mangled, 4, strlen(mangled)); if (!ends_with(rest, "@@")) return ""; rest = substr(rest, 0, strlen(rest) - 2); if (rest == "") return ""; auto i; auto n = strlen(rest); auto cur = ""; auto result = ""; for (i = 0; i < n; i = i + 1) { auto c = substr(rest, i, i + 1); if (c == "@") { if (cur != "") { auto seg = cleanup_template_segment(cur); if (result == "") result = seg; else result = seg + "::" + result; } cur = ""; } else { cur = cur + c; } } if (cur != "") { auto seg2 = cleanup_template_segment(cur); if (result == "") result = seg2; else result = seg2 + "::" + result; } return result; } // ========================================================================= // v5.2: leitor de string C RAW (le bytes ate \0 sem depender do IDA // ter definido a string). Substitui o que create_strlit fazia, agora // que essa funcao mudou de assinatura no 9.x e nao podemos mais usar. // ========================================================================= static read_c_string_raw(ea) { if (!is_loaded(ea)) return ""; auto out = ""; auto i = 0; auto max_len = 512; while (i < max_len) { auto b = get_wide_byte(ea + i); if (b == 0) break; if (b < 0x20 || b > 0x7E) break; out = out + sprintf("%c", b); i = i + 1; } return out; } // ========================================================================= // RTTI - CompleteObjectLocator (COL) // +0x00 signature (0 = x86, 1 = x64) // +0x04 offset // +0x08 cdOffset // +0x0C pTypeDescriptor (RVA em x64, ptr em x86) // +0x10 pClassDescriptor(RVA em x64, ptr em x86) // +0x14 pSelf (so x64, RVA) // ========================================================================= static col_read_field(col_ea, off) { auto v = get_wide_dword(col_ea + off); if (g_is_64) return rva_to_ea(v); return v; } static validate_col(col_ea) { if (!is_valid_data_ptr(col_ea)) return 0; auto sig = get_wide_dword(col_ea); auto expected = g_is_64 ? 1 : 0; if (sig != expected) return 0; auto offset = get_wide_dword(col_ea + 0x04); auto cdOffset = get_wide_dword(col_ea + 0x08); if (offset > 0x10000) return 0; if (cdOffset > 0x10000) return 0; auto type_desc = col_read_field(col_ea, 0x0C); if (!is_valid_data_ptr(type_desc)) return 0; auto chd = col_read_field(col_ea, 0x10); if (!is_valid_data_ptr(chd)) return 0; auto chd_sig = get_wide_dword(chd); if (chd_sig != 0) return 0; auto nb = get_wide_dword(chd + 0x08); if (nb == 0 || nb > 256) return 0; if (g_is_64) { auto self_rva = get_wide_dword(col_ea + 0x14); if (rva_to_ea(self_rva) != col_ea) return 0; } return 1; } static read_typedesc_name(td_ea) { if (!is_valid_data_ptr(td_ea)) return ""; auto name_ea = td_ea + (g_ptr_size * 2); auto mangled = get_strlit_contents(name_ea, -1, STRTYPE_C); if (mangled == 0 || mangled == "") { mangled = read_c_string_raw(name_ea); } if (mangled == 0 || mangled == "") return ""; return mangled; } static demangle_class_name(mangled) { if (mangled == 0 || mangled == "") return ""; if (!starts_with(mangled, ".?AV") && !starts_with(mangled, ".?AU")) return ""; auto wrapped = "??_R0" + substr(mangled, 1, strlen(mangled)) + "@8"; auto dem = demangle_name(wrapped, INF_LONG_DN); if (dem != 0 && dem != "") { if (starts_with(dem, "class ")) dem = substr(dem, 6, strlen(dem)); if (starts_with(dem, "struct ")) dem = substr(dem, 7, strlen(dem)); auto suf = " `RTTI Type Descriptor'"; if (ends_with(dem, suf)) dem = substr(dem, 0, strlen(dem) - strlen(suf)); if (dem != "") return dem; } auto man = manual_parse_rtti_name(mangled); if (man != "") return man; return mangled; } // ========================================================================= // CHD + BaseClassArray -> lista de pais (TD addresses CSV) // // CHD: // +0x00 signature (==0) // +0x04 attributes // +0x08 numBaseClasses // +0x0C pBaseClassArray (RVA x64 / ptr x86) // // BCD (cada entrada da BCA aponta pra um BCD): // +0x00 pTypeDescriptor // +0x04 numContainedBases // +0x08 PMD (mdisp, pdisp, vdisp - 12 bytes) // +0x14 attributes // +0x18 pClassDescriptor // // BCA[0] eh sempre a propria classe; pulamos. // ========================================================================= static parse_base_classes(col_ea) { auto chd = col_read_field(col_ea, 0x10); if (!is_valid_data_ptr(chd)) return ""; auto sig = get_wide_dword(chd); if (sig != 0) return ""; auto num_bases = get_wide_dword(chd + 0x08); if (num_bases <= 1 || num_bases > 64) return ""; auto bca_field = get_wide_dword(chd + 0x0C); auto bca_ea = g_is_64 ? rva_to_ea(bca_field) : bca_field; if (!is_valid_data_ptr(bca_ea)) return ""; auto out = ""; auto i; for (i = 1; i < num_bases; i = i + 1) { auto bcd_field = get_wide_dword(bca_ea + i * 4); auto bcd_ea = g_is_64 ? rva_to_ea(bcd_field) : bcd_field; if (!is_valid_data_ptr(bcd_ea)) continue; auto td_field = get_wide_dword(bcd_ea); auto td_ea = g_is_64 ? rva_to_ea(td_field) : td_field; if (!is_valid_data_ptr(td_ea)) continue; if (out == "") out = ltoa(td_ea, 10); else out = out + "," + ltoa(td_ea, 10); } return out; } static parents_csv_to_names(csv) { if (csv == "" || csv == 0) return ""; auto out = ""; auto buf = ""; auto i; auto n = strlen(csv); for (i = 0; i <= n; i = i + 1) { auto c = (i < n) ? substr(csv, i, i + 1) : ","; if (c == ",") { if (buf != "") { auto td = atol(buf); auto mang = read_typedesc_name(td); auto nm = (mang != "") ? demangle_class_name(mang) : "??"; if (out == "") out = nm; else out = out + ", " + nm; } buf = ""; } else { buf = buf + c; } } return out; } // ========================================================================= // CACHE + HIERARQUIA (arrays do IDB) // ========================================================================= static arr_init(name) { auto id = get_array_id(name); if (id != -1) delete_array(id); create_array(name); } static arr_set_long(name, key, val) { auto id = get_array_id(name); if (id == -1) return; set_array_long(id, key, val); } static arr_get_long(name, key) { auto id = get_array_id(name); if (id == -1) return -1; return get_array_element(AR_LONG, id, key); } static arr_set_str(name, key, val) { auto id = get_array_id(name); if (id == -1) return; set_array_string(id, key, val); } static arr_get_str(name, key) { auto id = get_array_id(name); if (id == -1) return ""; auto v = get_array_element(AR_STR, id, key); if (v == 0 || v == -1) return ""; return v; } static cache_init() { arr_init(ARR_VT_SEEN); arr_init(ARR_TD2VT); arr_init(ARR_VT2TD); arr_init(ARR_VT2COL); arr_init(ARR_VT2COUNT); arr_init(ARR_VT2NAME); arr_init(ARR_VT2PARENTS); arr_init(ARR_VT_LIST); arr_init(ARR_VT2SIZE); arr_init(ARR_VT2SINGLETON); arr_init(ARR_VT2OFFSET); g_vt_list_count = 0; } static cache_seen(ea) { return arr_get_long(ARR_VT_SEEN, ea) > 0; } static cache_mark(ea) { arr_set_long(ARR_VT_SEEN, ea, 1); } static hier_register(td_ea, vt_ea, col_ea, sname, count, parents_csv, col_offset) { arr_set_long(ARR_VT2TD, vt_ea, td_ea); arr_set_long(ARR_VT2COL, vt_ea, col_ea); arr_set_long(ARR_VT2COUNT, vt_ea, count); arr_set_long(ARR_VT2OFFSET, vt_ea, col_offset); arr_set_str (ARR_VT2NAME, vt_ea, sname); arr_set_str (ARR_VT2PARENTS,vt_ea, parents_csv); arr_set_long(ARR_VT_LIST, g_vt_list_count, vt_ea); g_vt_list_count = g_vt_list_count + 1; if (col_offset == 0) { if (arr_get_long(ARR_TD2VT, td_ea) <= 0) { arr_set_long(ARR_TD2VT, td_ea, vt_ea); } } } static hier_offset(vt_ea) { auto v = arr_get_long(ARR_VT2OFFSET, vt_ea); if (v == -1) return 0; return v; } static hier_col(vt_ea) { auto v = arr_get_long(ARR_VT2COL, vt_ea); if (v == -1) return BADADDR; return v; } static hier_vt_by_td(td_ea) { auto v = arr_get_long(ARR_TD2VT, td_ea); if (v == -1) return BADADDR; return v; } static hier_count(vt_ea) { auto v = arr_get_long(ARR_VT2COUNT, vt_ea); if (v == -1) return 0; return v; } static hier_name(vt_ea) { return arr_get_str(ARR_VT2NAME, vt_ea); } static hier_parents(vt_ea) { return arr_get_str(ARR_VT2PARENTS, vt_ea); } static hier_vt_at(idx) { auto v = arr_get_long(ARR_VT_LIST, idx); if (v == -1) return BADADDR; return v; } // ========================================================================= // PURECALL // ========================================================================= static is_pure_call(faddr) { if (faddr == BADADDR || faddr == 0) return 0; if (is_known_purecall_addr(faddr)) return 1; auto name = get_func_name(faddr); if (name != 0 && name != "") { if (strstr(name, "purecall") != -1) return 1; if (strstr(name, "pure_virtual") != -1) return 1; if (strstr(name, "cxa_pure_virtual") != -1) return 1; } auto fend = get_func_attr(faddr, FUNCATTR_END); if (fend == BADADDR) return 0; if ((fend - faddr) > 24) return 0; auto mnem = print_insn_mnem(faddr); if (mnem == "int" || mnem == "hlt" || mnem == "ud2") return 1; if (mnem == "jmp") { auto dref = get_first_dref_from(faddr); while (dref != BADADDR) { auto target_via_iat = get_wide_dword(dref); if (g_is_64) target_via_iat = get_qword(dref); if (is_known_purecall_addr(target_via_iat)) return 1; auto dn = get_name(dref); if (dn != 0 && dn != "") { if (strstr(dn, "purecall") != -1) return 1; if (strstr(dn, "pure_virtual") != -1) return 1; } dref = get_next_dref_from(faddr, dref); } auto tgt = get_first_fcref_from(faddr); if (tgt != BADADDR) { if (is_known_purecall_addr(tgt)) return 1; auto tn = get_func_name(tgt); if (tn != 0 && tn != "") { if (strstr(tn, "purecall") != -1) return 1; if (strstr(tn, "pure_virtual") != -1) return 1; } } } return 0; } // ========================================================================= // DESTRUTOR // ========================================================================= static is_destructor(faddr) { if (faddr == BADADDR || faddr == 0) return 0; auto name = get_func_name(faddr); if (name != 0 && name != "") { if (strstr(name, "::~") != -1) return 1; if (strstr(name, "??1") != -1) return 1; if (strstr(name, "??_E") != -1) return 1; if (strstr(name, "??_G") != -1) return 1; if (strstr(name, "destructor") != -1) return 1; if (strstr(name, "scalar_dtor")!= -1) return 1; if (strstr(name, "vector_dtor")!= -1) return 1; if (strstr(name, "__dtor") != -1) return 1; } auto fend = get_func_attr(faddr, FUNCATTR_END); if (fend == BADADDR) return 0; if ((fend - faddr) > 0x200) return 0; auto ea = faddr; auto guard = 0; while (ea < fend && ea != BADADDR && guard < 80) { auto m = print_insn_mnem(ea); if (m == "call" || m == "jmp") { auto tgt = get_first_fcref_from(ea); if (tgt != BADADDR) { auto tn = get_func_name(tgt); if (tn != 0 && tn != "") { if (strstr(tn, "operator delete") != -1) return 1; if (strstr(tn, "??3@") != -1) return 1; if (strstr(tn, "??_V") != -1) return 1; if (tn == "_free" || tn == "free" || tn == "_free_base") return 1; } } } ea = next_head(ea, fend); guard = guard + 1; } return 0; } // ========================================================================= // DETECCAO DE SIZEOF VIA operator new // Pattern em x86 thiscall: // push <imm> ; size // call ?? operator new // add esp, 4 ; (opcional) // mov ecx, eax ; this = obj // call <ctor> // ========================================================================= static find_object_size_from_call(call_ea) { auto fstart = get_func_attr(call_ea, FUNCATTR_START); if (fstart == BADADDR) fstart = call_ea - 0x80; auto cur = call_ea; auto guard = 0; while (guard < 15) { cur = prev_head(cur, fstart); if (cur == BADADDR || cur == 0 || cur < fstart) break; auto m = print_insn_mnem(cur); if (m == "ret" || m == "jmp") break; if (m == "call") { auto tgt = get_first_fcref_from(cur); if (tgt != BADADDR) { auto tn = get_func_name(tgt); if (tn != 0 && tn != "") { auto is_alloc = 0; if (strstr(tn, "operator new") != -1) is_alloc = 1; if (strstr(tn, "??2@") != -1) is_alloc = 1; if (strstr(tn, "_malloc") != -1) is_alloc = 1; if (tn == "malloc" || tn == "_malloc") is_alloc = 1; if (is_alloc) { auto pcur = cur; auto pg = 0; while (pg < 6) { pcur = prev_head(pcur, fstart); if (pcur == BADADDR || pcur < fstart) break; auto pm = print_insn_mnem(pcur); if (!g_is_64 && pm == "push" && get_operand_type(pcur, 0) == o_imm) { return get_operand_value(pcur, 0); } if (g_is_64 && pm == "mov" && get_operand_type(pcur, 0) == o_reg && get_operand_type(pcur, 1) == o_imm) { auto v = get_operand_value(pcur, 1); if (v > 0 && v < 0x10000) return v; } pg = pg + 1; } } } } return 0; } guard = guard + 1; } return 0; } static find_object_size_for_ctor(ctor_ea) { auto xr = get_first_cref_to(ctor_ea); while (xr != BADADDR) { auto sz = find_object_size_from_call(xr); if (sz > 0 && sz < 0x10000) return sz; xr = get_next_cref_to(ctor_ea, xr); } return 0; } // ========================================================================= // DETECCAO DE SINGLETON // Heuristica: depois da call ao construtor, se ha "mov ds:G, eax" com G // sendo um global valido, marca G como instancia singleton da classe. // ========================================================================= // Marca um global como singleton da classe. static mark_singleton(g_ea, class_name, ctor_ea) { if (DRY_RUN) return; auto cur_name = get_name(g_ea); if (cur_name == "" || starts_with(cur_name, "dword_") || starts_with(cur_name, "qword_") || starts_with(cur_name, "byte_") || starts_with(cur_name, "off_") || starts_with(cur_name, "unk_")) { set_name(g_ea, "g_" + class_name + "_instance", SN_NOWARN | SN_FORCE); } set_cmt(g_ea, "Singleton " + class_name + " ctor=0x" + ltoa(ctor_ea, 16), 1); } static detect_singleton_for_ctor(ctor_ea, class_name) { auto xr = get_first_cref_to(ctor_ea); while (xr != BADADDR) { auto caller_end = get_func_attr(xr, FUNCATTR_END); if (caller_end == BADADDR) caller_end = xr + 0x100; auto tracked = "|eax|rax|ecx|rcx|"; auto guard = 0; auto cur = xr; while (guard < 8) { cur = next_head(cur, caller_end); if (cur == BADADDR || cur >= caller_end) break; auto m = print_insn_mnem(cur); if (m == "call" || m == "ret" || m == "jmp") break; if (m == "mov") { auto t0 = get_operand_type(cur, 0); auto t1 = get_operand_type(cur, 1); if (t0 == o_mem && t1 == o_reg) { auto src_needle = "|" + print_operand(cur, 1) + "|"; if (strstr(tracked, src_needle) != -1) { auto g_ea = get_operand_value(cur, 0); if (is_loaded(g_ea) && g_ea > 0x1000) { mark_singleton(g_ea, class_name, ctor_ea); return g_ea; } } } if (t0 == o_reg && t1 == o_reg) { auto src_needle2 = "|" + print_operand(cur, 1) + "|"; if (strstr(tracked, src_needle2) != -1) { auto dst_needle = "|" + print_operand(cur, 0) + "|"; if (strstr(tracked, dst_needle) == -1) { tracked = tracked + substr(dst_needle, 1, strlen(dst_needle)); } } } } guard = guard + 1; } xr = get_next_cref_to(ctor_ea, xr); } return BADADDR; } // ========================================================================= // APLICACAO DE __thiscall + tipo "this" NAS FUNCOES VIRTUAIS // ========================================================================= // FIX A1: nao caimos mais em SetType (pode nao existir em IDA 9.x). // FIX A2: usamos TINFO_GUESSED (0) para nao sobrescrever tipos que o // usuario tenha definido manualmente. static apply_type_safe(ea, decl) { auto ti = parse_decl(decl, 0); if (ti == 0) return 0; return apply_type(ea, ti, 0); } static ensure_class_struct(sname_class) { auto sname = sname_class + "_t"; auto sid = get_struc_id(sname); if (sid != BADADDR) return sid; sid = add_struc(-1, sname, 0); if (sid == BADADDR) return BADADDR; auto flag = g_is_64 ? (FF_QWORD | FF_DATA) : (FF_DWORD | FF_DATA); add_struc_member(sid, "vptr", 0, flag, -1, g_ptr_size); return sid; } static apply_thiscall_to_vtable(vt_ea) { if (!APPLY_THISCALL_TYPES || DRY_RUN) return 0; auto sname = hier_name(vt_ea); auto count = hier_count(vt_ea); if (sname == "" || count == 0) return 0; auto effective_sname = sname; auto col_offset = hier_offset(vt_ea); if (col_offset != 0) { auto col = hier_col(vt_ea); if (col != BADADDR) { auto ptd = find_parent_td_for_offset(col, col_offset); if (ptd != 0) { auto pvt = hier_vt_by_td(ptd); if (pvt != BADADDR) { auto pn = hier_name(pvt); if (pn != "") effective_sname = pn; } } } } auto sid = ensure_class_struct(effective_sname); if (sid == BADADDR) return 0; auto applied = 0; auto i; for (i = 0; i < count; i = i + 1) { auto slot = vt_ea + i * g_ptr_size; auto faddr = read_ptr(slot); if (faddr == 0 || faddr == BADADDR) continue; if (is_pure_call(faddr)) continue; auto decl = "void __thiscall sub(struct " + effective_sname + "_t *this);"; if (apply_type_safe(faddr, decl)) applied = applied + 1; } return applied; } static apply_all_thiscall_types() { if (!APPLY_THISCALL_TYPES) return; log_info("=== Aplicando __thiscall + tipo this (em ordem topologica) ==="); auto tcount = topo_count(); auto total = (tcount > 0) ? tcount : g_vt_list_count; auto i; for (i = 0; i < total; i = i + 1) { if (user_cancelled()) return; auto vt = (tcount > 0) ? topo_at(i) : hier_vt_at(i); if (vt != BADADDR) { auto n = apply_thiscall_to_vtable(vt); g_stat_thiscall = g_stat_thiscall + n; } if ((i & 0x1F) == 0) { msg("[thiscall] %d/%d classes | %d metodos\n", i, total, g_stat_thiscall); } } log_info("__thiscall aplicado em " + ltoa(g_stat_thiscall, 10) + " metodos"); } // ========================================================================= // ANOTACAO DE CHAMADAS VIRTUAIS (call dword ptr [reg+N]) // ========================================================================= // // Plausibilidade v2: rastreia o registrador-base do call ate sua origem. // // 1) extrai o reg-base de "call [reg+N]" (ex: "eax" em "[eax+0Ch]") // 2) caminha pra tras ate o inicio da funcao (ou ate ret/jmp/call), // acompanhando o conjunto de regs que carregam aquele valor (lida // com propagacoes "mov ebx, eax" ao longo do prologo) // 3) declara plausivel quando encontra o write final que veio de // memoria (mov reg, [reg2+disp] ou lea reg, [reg2+disp]) - o // vptr load // 4) se o write veio de imediato/aritmetica/etc, descarta // // Janela aumentada pra 32 instrucoes (ou ate o inicio da funcao). // ========================================================================= static get_call_displ_base_reg(ea) { auto op = print_operand(ea, 0); if (op == 0 || op == "") return ""; auto bp = strstr(op, "["); if (bp == -1) return ""; auto i = bp + 1; auto n = strlen(op); auto reg = ""; while (i < n) { auto c = substr(op, i, i + 1); if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || (c >= "0" && c <= "9")) { reg = reg + c; } else { break; } i = i + 1; } return reg; } static is_likely_vcall(call_ea) { auto call_reg = get_call_displ_base_reg(call_ea); if (call_reg == "") return 0; auto fstart = get_func_attr(call_ea, FUNCATTR_START); if (fstart == BADADDR) fstart = call_ea - 0x100; auto tracked = "|" + call_reg + "|"; auto cur = call_ea; auto guard = 0; while (guard < 32) { cur = prev_head(cur, fstart); if (cur == BADADDR || cur < fstart) break; auto m = print_insn_mnem(cur); if (m == "ret" || m == "jmp" || m == "call") break; if (m == "mov" || m == "lea") { auto t0 = get_operand_type(cur, 0); if (t0 == o_reg) { auto dst = print_operand(cur, 0); auto dst_needle = "|" + dst + "|"; if (strstr(tracked, dst_needle) != -1) { auto t1 = get_operand_type(cur, 1); if (t1 == o_phrase || t1 == o_displ) return 1; if (t1 == o_reg) { auto src = print_operand(cur, 1); auto src_needle = "|" + src + "|"; if (strstr(tracked, src_needle) == -1) { tracked = tracked + substr(src_needle, 1, strlen(src_needle)); } } else { return 0; } } } } guard = guard + 1; } return 0; } static build_slot_methods_map() { arr_init(ARR_SLOT_METHODS); auto i; for (i = 0; i < g_vt_list_count; i = i + 1) { auto vt = hier_vt_at(i); if (vt == BADADDR) continue; auto sname = hier_name(vt); auto count = hier_count(vt); auto j; for (j = 0; j < count; j = j + 1) { auto cur = arr_get_str(ARR_SLOT_METHODS, j); if (cur == "") { arr_set_str(ARR_SLOT_METHODS, j, sname); } else { if (strlen(cur) < 400) { arr_set_str(ARR_SLOT_METHODS, j, cur + "," + sname); } } } } } static get_slot_summary(slot) { auto cur = arr_get_str(ARR_SLOT_METHODS, slot); if (cur == "") return ""; auto out = ""; auto buf = ""; auto emitted = 0; auto total = 0; auto i; auto n = strlen(cur); for (i = 0; i <= n; i = i + 1) { auto c = (i < n) ? substr(cur, i, i + 1) : ","; if (c == ",") { if (buf != "") { total = total + 1; if (emitted < VCALL_MAX_METHODS) { if (out != "") out = out + ", "; out = out + buf + "::v" + ltoa(slot, 10); emitted = emitted + 1; } } buf = ""; } else { buf = buf + c; } } if (total > VCALL_MAX_METHODS) { out = out + " (+" + ltoa(total - VCALL_MAX_METHODS, 10) + " mais)"; } return out; } static annotate_virtual_calls() { if (!ANNOTATE_VCALLS || DRY_RUN) return; log_info("=== Anotando chamadas virtuais ==="); build_slot_methods_map(); auto annotated = 0; auto func_count = 0; auto f = get_next_func(0); while (f != BADADDR) { if (user_cancelled()) return; func_count = func_count + 1; auto end = get_func_attr(f, FUNCATTR_END); auto ea = f; while (ea < end && ea != BADADDR) { auto m = print_insn_mnem(ea); if (m == "call" && get_operand_type(ea, 0) == o_displ) { auto disp = get_operand_value(ea, 0); if (disp >= 0 && disp < 0x800 && (disp - ((disp / g_ptr_size) * g_ptr_size)) == 0) { auto slot = disp / g_ptr_size; auto summary = get_slot_summary(slot); if (summary != "" && is_likely_vcall(ea)) { auto cur_cmt = get_cmt(ea, 0); auto can_set = 0; if (cur_cmt == "" || cur_cmt == 0) can_set = 1; else if (starts_with(cur_cmt, "vcall ")) can_set = 1; if (can_set) { set_cmt(ea, "vcall slot[" + ltoa(slot, 10) + "]: " + summary, 0); annotated = annotated + 1; } } } } ea = next_head(ea, end); } f = get_next_func(f); if ((func_count & 0xFF) == 0) { msg("[vcall] %d funcoes | %d call sites anotados\n", func_count, annotated); } } g_stat_vcalls = annotated; log_info("vcall: " + ltoa(annotated, 10) + " call sites anotados"); } // ========================================================================= // GERACAO DE wyd_classes.h (topological) // ========================================================================= static emit_class_header_rec(hf, vt_ea) { if (arr_get_long(ARR_HDR_EMITTED, vt_ea) > 0) return; arr_set_long(ARR_HDR_EMITTED, vt_ea, 1); if (hier_offset(vt_ea) != 0) return; auto parents_csv = hier_parents(vt_ea); auto parent_names_buf = ""; auto parent_count = 0; auto buf = ""; auto i; auto n = strlen(parents_csv); for (i = 0; i <= n; i = i + 1) { auto c = (i < n) ? substr(parents_csv, i, i + 1) : ","; if (c == ",") { if (buf != "") { auto td = atol(buf); auto pvt = hier_vt_by_td(td); if (pvt != BADADDR) { emit_class_header_rec(hf, pvt); auto pname = hier_name(pvt); if (parent_names_buf == "") parent_names_buf = pname; else parent_names_buf = parent_names_buf + "|" + pname; parent_count = parent_count + 1; } } buf = ""; } else { buf = buf + c; } } auto cname = hier_name(vt_ea); auto count = hier_count(vt_ea); auto size = arr_get_long(ARR_VT2SIZE, vt_ea); auto sgl = arr_get_long(ARR_VT2SINGLETON, vt_ea); fprintf(hf, "// vtable=0x%x methods=%d", vt_ea, count); if (size > 0) fprintf(hf, " sizeof=0x%x", size); if (sgl != -1 && sgl != BADADDR) fprintf(hf, " singleton=0x%x", sgl); if (parent_count > 0) { fprintf(hf, " inherits="); auto pn = parent_names_buf; auto j; auto pbuf = ""; auto first_p = 1; auto pl = strlen(pn); for (j = 0; j <= pl; j = j + 1) { auto pc = (j < pl) ? substr(pn, j, j + 1) : "|"; if (pc == "|") { if (pbuf != "") { if (!first_p) fprintf(hf, ","); fprintf(hf, "%s", pbuf); first_p = 0; } pbuf = ""; } else { pbuf = pbuf + pc; } } } fprintf(hf, "\n"); fprintf(hf, "struct vtable_%s_t;\n", cname); fprintf(hf, "struct %s {\n", cname); fprintf(hf, " struct vtable_%s_t *vptr;\n", cname); if (size > g_ptr_size) { fprintf(hf, " char data[0x%x];\n", size - g_ptr_size); } fprintf(hf, " // %d virtual methods:\n", count); auto k; for (k = 0; k < count; k = k + 1) { auto slot = vt_ea + k * g_ptr_size; auto faddr = read_ptr(slot); auto fname = get_func_name(faddr); auto pos = strstr(fname, "__"); auto mp; if (pos != -1) mp = substr(fname, pos + 2, strlen(fname)); else if (fname != "" && fname != 0) mp = fname; else mp = "vmethod_" + ltoa(k, 10); fprintf(hf, " // [%d] @ 0x%x %s", k, faddr, mp); if (is_pure_call(faddr)) fprintf(hf, " (pure)"); fprintf(hf, "\n"); } fprintf(hf, "};\n\n"); g_stat_header_classes = g_stat_header_classes + 1; } static emit_cpp_header(out_path) { if (!EMIT_CPP_HEADER) return; log_info("=== Gerando header C++ ==="); auto hf = fopen(out_path, "w"); if (hf == 0) { log_warn("Nao consegui abrir " + out_path); return; } fprintf(hf, "// =====================================================\n"); fprintf(hf, "// Gerado por Vtable Analyzer Pro v5.1\n"); fprintf(hf, "// Total de classes: %d\n", g_vt_list_count); fprintf(hf, "// Use no IDA: File > Load file > Parse C header file...\n"); fprintf(hf, "// para importar como Local Types.\n"); fprintf(hf, "// =====================================================\n"); fprintf(hf, "\n#pragma pack(push, 1)\n\n"); arr_init(ARR_HDR_EMITTED); auto i; for (i = 0; i < g_vt_list_count; i = i + 1) { if (user_cancelled()) break; auto vt = hier_vt_at(i); if (vt != BADADDR) emit_class_header_rec(hf, vt); } fprintf(hf, "#pragma pack(pop)\n"); fclose(hf); log_info("Header gerado: " + out_path + " (" + ltoa(g_stat_header_classes, 10) + " classes)"); } // ========================================================================= // CONSTRUTOR / DESTRUTOR via xref // ========================================================================= static rename_constructors(vtable_ea, sname_class) { auto xr = get_first_dref_to(vtable_ea); auto ctor_idx = 0; auto dtor_idx = 0; auto first_ctor = BADADDR; while (xr != BADADDR) { auto fstart = get_func_attr(xr, FUNCATTR_START); auto xr_mnem = print_insn_mnem(xr); auto vtable_assign = (xr_mnem == "mov" || xr_mnem == "lea"); if (fstart != BADADDR && vtable_assign) { auto fend = get_func_attr(fstart, FUNCATTR_END); auto fsize = fend - fstart; auto rel = xr - fstart; auto early = (fsize > 0) && (rel < (fsize / 2 + 8) || rel < 64); if (early) { auto cur_name = get_func_name(fstart); auto auto_named = (cur_name == "" || starts_with(cur_name, "sub_")); auto is_dtor = is_destructor(fstart); if (is_dtor) { g_stat_dtors = g_stat_dtors + 1; if ((auto_named || RENAME_OVERRIDES) && !DRY_RUN) { auto dname; if (dtor_idx == 0) dname = sname_class + "__dtor"; else dname = sname_class + "__dtor_" + ltoa(dtor_idx, 10); set_name(fstart, dname, SN_NOWARN | SN_FORCE); set_color(fstart, CIC_FUNC, COLOR_DTOR); log_info(" [DTOR-renamed] " + dname + " @ 0x" + ltoa(fstart, 16)); } else { if (!DRY_RUN) set_color(fstart, CIC_FUNC, COLOR_DTOR); log_info(" [DTOR-detected] " + cur_name + " @ 0x" + ltoa(fstart, 16)); } dtor_idx = dtor_idx + 1; } else { g_stat_ctors = g_stat_ctors + 1; if ((auto_named || RENAME_OVERRIDES) && !DRY_RUN) { auto cname2; if (ctor_idx == 0) cname2 = sname_class + "__ctor"; else cname2 = sname_class + "__ctor_" + ltoa(ctor_idx, 10); set_name(fstart, cname2, SN_NOWARN | SN_FORCE); set_color(fstart, CIC_FUNC, COLOR_CTOR); log_info(" [CTOR-renamed] " + cname2 + " @ 0x" + ltoa(fstart, 16)); } else { if (!DRY_RUN) set_color(fstart, CIC_FUNC, COLOR_CTOR); log_info(" [CTOR-detected] " + cur_name + " @ 0x" + ltoa(fstart, 16)); } ctor_idx = ctor_idx + 1; if (first_ctor == BADADDR) first_ctor = fstart; } } } xr = get_next_dref_to(vtable_ea, xr); } if (first_ctor != BADADDR) { if (DETECT_OBJECT_SIZES) { auto size = find_object_size_for_ctor_v2(first_ctor); if (size > 0 && size < 0x10000) { arr_set_long(ARR_VT2SIZE, vtable_ea, size); if (!DRY_RUN) { set_cmt(vtable_ea, sprintf("vtable de %s sizeof=0x%X (%d bytes)", sname_class, size, size), 1); } g_stat_sizes = g_stat_sizes + 1; log_info(" [SIZE] sizeof(" + sname_class + ") = 0x" + ltoa(size, 16)); } } if (DETECT_SINGLETONS) { auto sgl = detect_singleton_for_ctor(first_ctor, sname_class); if (sgl == BADADDR) { sgl = detect_singleton_aggressive(first_ctor, sname_class); } if (sgl != BADADDR) { arr_set_long(ARR_VT2SINGLETON, vtable_ea, sgl); g_stat_singletons = g_stat_singletons + 1; log_info(" [SGTN] " + sname_class + " instance @ 0x" + ltoa(sgl, 16)); } } } } // ========================================================================= // TAMANHO DA VTABLE // ========================================================================= static is_another_vtable_starting_here(slot_ea) { auto xr = get_first_dref_to(slot_ea); while (xr != BADADDR) { auto sn = seg_name_of(xr); if (strstr(sn, ".rdata") != -1 || strstr(sn, ".data") != -1) return 1; xr = get_next_dref_to(slot_ea, xr); } return 0; } static vtable_size(vtable_ea) { auto count = 0; auto cur = vtable_ea; while (count < MAX_VTABLE_METHODS) { auto p = read_ptr(cur); if (!is_valid_code_ptr(p)) break; if (count > 0 && is_another_vtable_starting_here(cur)) break; count = count + 1; cur = cur + g_ptr_size; } return count; } // ========================================================================= // STRUCT DA VTABLE // ========================================================================= static create_vtable_struct(sname_class, vtable_ea, count) { if (!CREATE_STRUCTS) return; if (DRY_RUN) return; auto sname = "vtable_" + sname_class + "_t"; auto sid = get_struc_id(sname); if (sid != BADADDR) del_struc(sid); sid = add_struc(-1, sname, 0); if (sid == BADADDR) { log_warn(" Falha ao criar struct " + sname); return; } auto i; for (i = 0; i < count; i = i + 1) { auto slot = vtable_ea + (i * g_ptr_size); auto faddr = read_ptr(slot); auto fname = get_func_name(faddr); auto member; if (fname == 0 || fname == "" || starts_with(fname, "sub_")) { member = "vmethod_" + ltoa(i, 10); } else { auto pos = strstr(fname, "::"); if (pos != -1) member = substr(fname, pos + 2, strlen(fname)); else member = fname; member = sanitize_name(member); } auto base_member = member; auto suffix = 0; while (get_member_offset(sid, member) != -1 && suffix < 64) { suffix = suffix + 1; member = base_member + "_" + ltoa(suffix, 10); } auto flag = g_is_64 ? (FF_QWORD | FF_DATA) : (FF_DWORD | FF_DATA); add_struc_member(sid, member, i * g_ptr_size, flag, -1, g_ptr_size); } log_info(" [STRUCT] " + sname + " (" + ltoa(count, 10) + " slots)"); } // ========================================================================= // EMISSAO DE JSON (uma classe) // ========================================================================= // // FIX item 2: emit_parents_json itera direto sobre o CSV numerico de TDs, // sem nunca passar pela string "pretty" (que tinha ", " e quebrava com // templates demangled). // static emit_parents_json(jf, csv) { if (jf == 0 || csv == "" || csv == 0) return; auto buf = ""; auto first = 1; auto i; auto n = strlen(csv); for (i = 0; i <= n; i = i + 1) { auto c = (i < n) ? substr(csv, i, i + 1) : ","; if (c == ",") { if (buf != "") { auto td = atol(buf); auto mang = read_typedesc_name(td); auto nm = (mang != "") ? demangle_class_name(mang) : "??"; if (!first) fprintf(jf, ", "); fprintf(jf, "\"%s\"", json_escape(nm)); first = 0; } buf = ""; } else { buf = buf + c; } } } static emit_class_json(cname, sname, mangled, vt_ea, col_ea, count, parents_csv) { auto jf = g_json_handle; if (jf == 0) return; if (!g_json_first) fprintf(jf, ",\n"); g_json_first = 0; fprintf(jf, " {\n"); fprintf(jf, " \"class\": \"%s\",\n", json_escape(cname)); fprintf(jf, " \"sanitized\": \"%s\",\n", json_escape(sname)); fprintf(jf, " \"mangled\": \"%s\",\n", json_escape(mangled)); fprintf(jf, " \"vtable_ea\": \"0x%x\",\n", vt_ea); fprintf(jf, " \"col_ea\": \"0x%x\",\n", col_ea); fprintf(jf, " \"method_count\": %d,\n", count); fprintf(jf, " \"parents\": ["); emit_parents_json(jf, parents_csv); fprintf(jf, "],\n"); auto col_offset_v = arr_get_long(ARR_VT2OFFSET, vt_ea); if (col_offset_v == -1) col_offset_v = 0; if (col_offset_v != 0) { fprintf(jf, " \"is_secondary\": true,\n"); fprintf(jf, " \"sub_offset\": %d,\n", col_offset_v); } auto size_v = arr_get_long(ARR_VT2SIZE, vt_ea); auto sgl_v = arr_get_long(ARR_VT2SINGLETON, vt_ea); if (size_v > 0) fprintf(jf, " \"sizeof\": %d,\n", size_v); if (sgl_v != -1 && sgl_v != BADADDR) fprintf(jf, " \"singleton_ea\": \"0x%x\",\n", sgl_v); fprintf(jf, " \"methods\": [\n"); auto j; for (j = 0; j < count; j = j + 1) { auto slot = vt_ea + (j * g_ptr_size); auto faddr = read_ptr(slot); auto kind = "vmethod"; if (is_pure_call(faddr)) kind = "pure"; else if (j <= 1 && is_destructor(faddr)) kind = "deleting_dtor"; fprintf(jf, " {\"index\": %d, \"slot_ea\": \"0x%x\", \"func_ea\": \"0x%x\", \"name\": \"%s\", \"kind\": \"%s\"}", j, slot, faddr, json_escape(get_func_name(faddr)), kind); if (j < count - 1) fprintf(jf, ","); fprintf(jf, "\n"); } fprintf(jf, " ]\n"); fprintf(jf, " }"); } // ========================================================================= // v5.3: FILTRO DE FRAMEWORK CLASSES // Evita poluir o output com classes do MFC/STL/ATL que o usuario raramente // quer mexer. Identificacao por prefixo de nome. // ========================================================================= static is_framework_class(name) { if (name == 0 || name == "") return 0; if (starts_with(name, "std::")) return 1; if (starts_with(name, "ATL::")) return 1; if (starts_with(name, "Gdiplus::")) return 1; if (starts_with(name, "Json::")) return 1; if (starts_with(name, "CMFC")) return 1; if (starts_with(name, "CMap<")) return 1; if (starts_with(name, "CArray<")) return 1; if (starts_with(name, "CList<")) return 1; if (starts_with(name, "CTypedPtr")) return 1; if (starts_with(name, "CResourcePool<")) return 1; if (starts_with(name, "DataPool<")) return 1; if (starts_with(name, "COle")) return 1; if (starts_with(name, "CDoc")) return 1; if (starts_with(name, "CDock")) return 1; if (starts_with(name, "CWnd")) return 1; if (starts_with(name, "CWin")) return 1; if (starts_with(name, "CCmd")) return 1; if (starts_with(name, "_AFX")) return 1; if (starts_with(name, "AFX_")) return 1; if (strstr(name, "tpl_") != -1) return 1; if (name == "type_info") return 1; return 0; } // ========================================================================= // v5.3: SIZEOF DETECTOR v2 // Tenta multiplos padroes pra detectar sizeof do objeto: // 1. push imm + call new (padrao MSVC stdlib) // 2. mov ecx/edx, imm + call <custom_alloc> // 3. mov [esp], imm + call <alloc> // 4. (fallback) inferir pelo max offset escrito em [this+N] no body do ctor // ========================================================================= static find_object_size_v2_caller(call_ea) { auto fstart = get_func_attr(call_ea, FUNCATTR_START); if (fstart == BADADDR) fstart = call_ea - 0x80; auto cur = call_ea; auto guard = 0; while (guard < 20) { cur = prev_head(cur, fstart); if (cur == BADADDR || cur == 0 || cur < fstart) break; auto m = print_insn_mnem(cur); if (m == "ret" || m == "jmp") break; if (m == "call") { auto tgt = get_first_fcref_from(cur); if (tgt != BADADDR) { auto tn = get_func_name(tgt); if (tn != 0 && tn != "") { auto is_alloc = 0; if (strstr(tn, "operator new") != -1) is_alloc = 1; if (strstr(tn, "??2@") != -1) is_alloc = 1; if (strstr(tn, "_malloc") != -1) is_alloc = 1; if (tn == "malloc" || tn == "_malloc") is_alloc = 1; if (strstr(tn, "Alloc") != -1) is_alloc = 1; if (strstr(tn, "alloc") != -1) is_alloc = 1; if (strstr(tn, "MemNew") != -1) is_alloc = 1; if (is_alloc) { auto pcur = cur; auto pg = 0; while (pg < 8) { pcur = prev_head(pcur, fstart); if (pcur == BADADDR || pcur < fstart) break; auto pm = print_insn_mnem(pcur); if (pm == "push" && get_operand_type(pcur, 0) == o_imm) { return get_operand_value(pcur, 0); } if (pm == "mov" && get_operand_type(pcur, 0) == o_reg && get_operand_type(pcur, 1) == o_imm) { auto v = get_operand_value(pcur, 1); if (v > 0 && v < 0x10000) return v; } if (pm == "mov" && get_operand_type(pcur, 0) == o_displ && get_operand_type(pcur, 1) == o_imm) { auto v2 = get_operand_value(pcur, 1); if (v2 > 0 && v2 < 0x10000) return v2; } pg = pg + 1; } } } } return 0; } guard = guard + 1; } return 0; } static infer_size_from_ctor_body(ctor_ea) { if (!SIZE_INFER_FROM_BODY) return 0; auto fend = get_func_attr(ctor_ea, FUNCATTR_END); if (fend == BADADDR) return 0; if ((fend - ctor_ea) > 0x800) return 0; auto max_off = 0; auto ea = ctor_ea; auto guard = 0; while (ea < fend && ea != BADADDR && guard < SIZE_BODY_SCAN_LIMIT) { auto i; for (i = 0; i < 2; i = i + 1) { if (get_operand_type(ea, i) == o_displ) { auto disp = get_operand_value(ea, i); if (disp > max_off && disp < 0x10000) { auto op_str = print_operand(ea, i); if (strstr(op_str, "ecx") != -1 || strstr(op_str, "esi") != -1 || strstr(op_str, "edi") != -1 || strstr(op_str, "ebx") != -1) { max_off = disp; } } } } ea = next_head(ea, fend); guard = guard + 1; } if (max_off == 0) return 0; return max_off + g_ptr_size; } static find_object_size_for_ctor_v2(ctor_ea) { auto xr = get_first_cref_to(ctor_ea); while (xr != BADADDR) { auto sz = find_object_size_v2_caller(xr); if (sz > 0 && sz < 0x10000) return sz; xr = get_next_cref_to(ctor_ea, xr); } auto body_sz = infer_size_from_ctor_body(ctor_ea); if (body_sz > 0) return body_sz; return 0; } // ========================================================================= // v5.3: SINGLETON DETECTOR v2 (mais agressivo) // Alem de "mov ds:G, eax" pos-ctor, detecta: // - Funcao curta que retorna sempre o mesmo global ("GetInstance" pattern) // - Lazy init pattern: "if (!g_X) g_X = new X(); return g_X;" // ========================================================================= static detect_singleton_aggressive(ctor_ea, class_name) { if (!SINGLETON_AGGRESSIVE) return BADADDR; auto xr = get_first_cref_to(ctor_ea); while (xr != BADADDR) { auto caller_start = get_func_attr(xr, FUNCATTR_START); if (caller_start == BADADDR) { xr = get_next_cref_to(ctor_ea, xr); continue; } auto caller_end = get_func_attr(caller_start, FUNCATTR_END); auto caller_size = caller_end - caller_start; if (caller_size > 0 && caller_size < 0x100) { auto cur = caller_start; auto g = 0; while (cur < caller_end && cur != BADADDR && g < 30) { auto m = print_insn_mnem(cur); if (m == "mov" && get_operand_type(cur, 0) == o_reg && get_operand_type(cur, 1) == o_mem) { auto g_ea = get_operand_value(cur, 1); if (is_loaded(g_ea) && g_ea > 0x1000) { auto cn = get_func_name(caller_start); if (cn != "" && (strstr(cn, "etInstance") != -1 || strstr(cn, "etSingleton") != -1 || strstr(cn, "_instance") != -1 || caller_size < 0x40)) { mark_singleton(g_ea, class_name, ctor_ea); return g_ea; } } } cur = next_head(cur, caller_end); g = g + 1; } } xr = get_next_cref_to(ctor_ea, xr); } return BADADDR; } // ========================================================================= // ANALISE DE UMA VTABLE // ========================================================================= static analyze_vtable(ea) { if (cache_seen(ea)) return 0; auto first_ptr = read_ptr(ea); if (!is_valid_code_ptr(first_ptr)) return 0; auto col_ea = read_ptr(ea - g_ptr_size); if (!validate_col(col_ea)) return 0; auto type_desc = col_read_field(col_ea, 0x0C); auto mangled = read_typedesc_name(type_desc); if (mangled == "") return 0; auto cname = demangle_class_name(mangled); if (cname == "") return 0; if (EXCLUDE_FRAMEWORK_CLASSES && is_framework_class(cname)) { g_stat_filtered = g_stat_filtered + 1; cache_mark(ea); return 0; } auto col_offset = get_wide_dword(col_ea + 0x04); auto sname = sanitize_name(cname); auto display_name = cname; if (col_offset != 0) { sname = sname + "_sub_" + ltoa(col_offset, 16); display_name = cname + " [secondary @ +0x" + ltoa(col_offset, 16) + "]"; } auto count = vtable_size(ea); if (count < MIN_VTABLE_METHODS) return 0; auto parents_csv = parse_base_classes(col_ea); auto parents_pretty; if (col_offset != 0) { auto ptd = find_parent_td_for_offset(col_ea, col_offset); if (ptd != 0) { auto pmang = read_typedesc_name(ptd); parents_pretty = (pmang != "") ? demangle_class_name(pmang) : "??"; } else { parents_pretty = ""; } } else { parents_pretty = parents_csv_to_names(parents_csv); } log_info("Classe: " + display_name + " (" + ltoa(count, 10) + " metodos) vtable=0x" + ltoa(ea, 16) + " COL=0x" + ltoa(col_ea, 16)); log_info(" mangled = " + mangled); if (parents_pretty != "") { if (col_offset != 0) log_info(" base = " + parents_pretty); else log_info(" pais = " + parents_pretty); } g_stat_classes = g_stat_classes + 1; g_stat_methods = g_stat_methods + count; if (!DRY_RUN) { set_name(ea, "vtable_" + sname, SN_NOWARN | SN_FORCE); set_name(col_ea, "RTTI_COL_" + sname, SN_NOWARN | SN_FORCE); set_color(col_ea, CIC_ITEM, COLOR_RTTI_COL); set_cmt(col_ea, "CompleteObjectLocator de " + cname + (col_offset != 0 ? sprintf(" (offset 0x%X)", col_offset) : ""), 1); if (col_offset == 0) { set_name(type_desc, "RTTI_TD_" + sname, SN_NOWARN | SN_FORCE); set_color(type_desc, CIC_ITEM, COLOR_TYPE_DESC); set_cmt(type_desc, "TypeDescriptor de " + cname, 1); } if (col_offset != 0) { set_cmt(ea, "vtable secundaria de " + cname + " base " + (parents_pretty != "" ? parents_pretty : "??") + " @ offset 0x" + ltoa(col_offset, 16), 1); } else if (parents_pretty != "") { set_cmt(ea, "vtable de " + cname + " herda de: " + parents_pretty, 1); } else { set_cmt(ea, "vtable de " + cname, 1); } } auto i; for (i = 0; i < count; i = i + 1) { auto slot = ea + (i * g_ptr_size); auto faddr = read_ptr(slot); auto vname; auto vcolor = COLOR_VFUNC; if (is_pure_call(faddr)) { vname = sname + "__pure_v" + ltoa(i, 10); vcolor = COLOR_PURE; g_stat_pures = g_stat_pures + 1; } else if (i <= 1 && is_destructor(faddr)) { vname = sname + "__deleting_dtor_v" + ltoa(i, 10); vcolor = COLOR_DTOR; } else { vname = sname + "__vmethod_" + ltoa(i, 10); } auto cur_name = get_func_name(faddr); auto can_rename = (cur_name == "" || starts_with(cur_name, "sub_") || RENAME_OVERRIDES); if (!DRY_RUN && can_rename) { if (set_name(faddr, vname, SN_NOWARN | SN_FORCE)) { g_stat_renamed = g_stat_renamed + 1; } } if (!DRY_RUN) { set_color(slot, CIC_ITEM, COLOR_VTABLE_SLOT); set_color(faddr, CIC_FUNC, vcolor); set_cmt(slot, sprintf("[%d] +0x%X -> %s", i, i * g_ptr_size, vname), 0); } } create_vtable_struct(sname, ea, count); if (col_offset == 0) rename_constructors(ea, sname); hier_register(type_desc, ea, col_ea, sname, count, parents_csv, col_offset); emit_class_json(display_name, sname, mangled, ea, col_ea, count, parents_csv); cache_mark(ea); return count; } // ========================================================================= // STRING-FIRST: helpers // ========================================================================= // v5.2 DEBUG: loga em detalhe cada xref do TD e o resultado da validacao // pra entender por que estamos perdendo as vtables. static validate_col_verbose(col_ea) { if (!is_valid_data_ptr(col_ea)) { msg(" [reject] data_ptr invalido\n"); return 0; } auto sig = get_wide_dword(col_ea); auto expected = g_is_64 ? 1 : 0; if (sig != expected) { msg(" [reject] sig=0x%x esperado=%d\n", sig, expected); return 0; } auto offset = get_wide_dword(col_ea + 0x04); auto cdOffset = get_wide_dword(col_ea + 0x08); if (offset > 0x10000) { msg(" [reject] offset=0x%x grande demais\n", offset); return 0; } if (cdOffset > 0x10000) { msg(" [reject] cdOffset=0x%x grande demais\n", cdOffset); return 0; } auto type_desc = col_read_field(col_ea, 0x0C); if (!is_valid_data_ptr(type_desc)) { msg(" [reject] type_desc=0x%x invalido\n", type_desc); return 0; } auto chd = col_read_field(col_ea, 0x10); if (!is_valid_data_ptr(chd)) { msg(" [reject] chd=0x%x invalido\n", chd); return 0; } auto chd_sig = get_wide_dword(chd); if (chd_sig != 0) { msg(" [reject] chd_sig=0x%x (esperado 0)\n", chd_sig); return 0; } auto nb = get_wide_dword(chd + 0x08); if (nb == 0 || nb > 256) { msg(" [reject] num_bases=%d\n", nb); return 0; } if (g_is_64) { auto self_rva = get_wide_dword(col_ea + 0x14); if (rva_to_ea(self_rva) != col_ea) { msg(" [reject] pSelf nao bate\n"); return 0; } } msg(" [accept] COL valido!\n"); return 1; } static process_typedesc_xrefs(td_ea) { auto found = 0; auto xr = get_first_dref_to(td_ea); while (xr != BADADDR) { auto col_candidate = xr - 0x0C; if (validate_col(col_candidate)) { auto xv = get_first_dref_to(col_candidate); while (xv != BADADDR) { auto vtable_candidate = xv + g_ptr_size; if (is_valid_code_ptr(read_ptr(vtable_candidate))) { if (analyze_vtable(vtable_candidate) > 0) found = found + 1; } xv = get_next_dref_to(col_candidate, xv); } } xr = get_next_dref_to(td_ea, xr); } return found; } static byte_at(ea) { return get_wide_byte(ea); } static scan_via_rtti_strings() { log_info("=== Modo string-first ==="); auto total = 0; auto strings_found = 0; auto iters = 0; auto seg; for (seg = get_first_seg(); seg != BADADDR; seg = get_next_seg(seg)) { auto sn = get_segm_name(seg); if (strstr(sn, ".rdata") == -1 && strstr(sn, ".data") == -1) continue; auto ss = get_segm_start(seg); auto se = get_segm_end(seg); if (STRING_SCAN_MAX_SEG_SIZE > 0 && (se - ss) > STRING_SCAN_MAX_SEG_SIZE) { log_warn("Pulando " + sn + " (tamanho " + ltoa(se - ss, 16) + " > limite " + ltoa(STRING_SCAN_MAX_SEG_SIZE, 16) + ")"); continue; } log_info("Procurando .?AV/.?AU em " + sn + " [0x" + ltoa(ss, 16) + " - 0x" + ltoa(se, 16) + "]"); auto ea = ss; while (ea < se - 8) { if (user_cancelled()) return total; iters = iters + 1; if ((iters % (PROGRESS_EVERY * 4)) == 0) { msg("[string-scan] 0x%x | strings: %d | classes: %d\n", ea, strings_found, g_stat_classes); } if (byte_at(ea) == 0x2E && byte_at(ea + 1) == 0x3F && byte_at(ea + 2) == 0x41 && (byte_at(ea + 3) == 0x56 || byte_at(ea + 3) == 0x55)) { auto mangled = read_c_string_raw(ea); if (mangled != 0 && mangled != "" && ends_with(mangled, "@@")) { strings_found = strings_found + 1; auto td_ea = ea - (g_ptr_size * 2); if (is_valid_data_ptr(td_ea)) { total = total + process_typedesc_xrefs(td_ea); } auto sl = strlen(mangled); ea = ea + sl + 1; } else { ea = ea + 1; } } else { ea = ea + 1; } } } log_info("string-first: " + ltoa(strings_found, 10) + " strings RTTI vistas, " + ltoa(total, 10) + " novas vtables analisadas"); return total; } // ========================================================================= // PONTEIRO-SEQUENCIAL // ========================================================================= static scan_via_pointers() { log_info("=== Modo ponteiro-sequencial ==="); auto total = 0; auto iters = 0; auto seg; for (seg = get_first_seg(); seg != BADADDR; seg = get_next_seg(seg)) { auto sn = get_segm_name(seg); auto match = (strstr(sn, ".rdata") != -1); if (SCAN_DATA_TOO && strstr(sn, ".data") != -1 && strstr(sn, ".rdata") == -1) match = 1; if (!match) continue; auto ss = get_segm_start(seg); auto se = get_segm_end(seg); log_info("Varrendo " + sn + " [0x" + ltoa(ss, 16) + " - 0x" + ltoa(se, 16) + "]"); auto ea = ss; while (ea < se) { if (user_cancelled()) return total; iters = iters + 1; if ((iters % PROGRESS_EVERY) == 0) { msg("[ponteiro-scan] 0x%x | classes: %d | metodos: %d\n", ea, g_stat_classes, g_stat_methods); } auto consumed = analyze_vtable(ea); if (consumed > 0) { total = total + 1; ea = ea + (consumed * g_ptr_size); } else { ea = ea + g_ptr_size; } } } log_info("ponteiro-scan: " + ltoa(total, 10) + " vtables analisadas"); return total; } // ========================================================================= // BRUTE-FORCE RTTI (x64 e x86) - fallback quando IDA nao tracou xrefs // // Estrategia identica em ambas arquiteturas, apenas a assinatura do COL // e o tamanho do ponteiro mudam: // // 1) varremos .rdata em alinhamento 4 procurando COL candidatos: // x64: signature == 1 e pSelf RVA consistente // x86: signature == 0 e validate_col passa // 2) para cada COL valido, tentamos xrefs; se nao houver, fazemos // um segundo scan procurando ptrs (qword em x64, dword em x86) // que apontam pro COL - isso eh vtable[-1]. // // ========================================================================= static align_up_4(ea) { auto rem = ea - ((ea / 4) * 4); if (rem == 0) return ea; return ea + (4 - rem); } static align_up_8(ea) { auto rem = ea - ((ea / 8) * 8); if (rem == 0) return ea; return ea + (8 - rem); } static brute_force_vt_for_col(col_ea) { auto found = 0; auto seg; for (seg = get_first_seg(); seg != BADADDR; seg = get_next_seg(seg)) { auto sn = get_segm_name(seg); if (strstr(sn, ".rdata") == -1) continue; auto ss = get_segm_start(seg); auto se = get_segm_end(seg); auto ea = g_is_64 ? align_up_8(ss) : align_up_4(ss); while (ea < se - g_ptr_size * 2) { if (user_cancelled()) return found; auto cur_val = read_ptr(ea); if (cur_val == col_ea) { auto vt = ea + g_ptr_size; if (is_valid_code_ptr(read_ptr(vt))) { if (analyze_vtable(vt) > 0) found = found + 1; } } ea = ea + g_ptr_size; } } return found; } static brute_force_rtti() { if (g_is_64) { if (!BRUTE_FORCE_X64_RVA) return 0; } else { if (!BRUTE_FORCE_X86) return 0; } auto expected_sig = g_is_64 ? 1 : 0; auto arch_label = g_is_64 ? "x64" : "x86"; log_info("=== Brute-force " + arch_label + " (COL signature=" + ltoa(expected_sig, 10) + ") ==="); auto found = 0; auto iters = 0; auto seg; for (seg = get_first_seg(); seg != BADADDR; seg = get_next_seg(seg)) { if (user_cancelled()) return found; auto sn = get_segm_name(seg); if (strstr(sn, ".rdata") == -1) continue; auto ss = get_segm_start(seg); auto se = get_segm_end(seg); log_info("Brute-scan em " + sn + " [0x" + ltoa(ss, 16) + " - 0x" + ltoa(se, 16) + "]"); auto ea = align_up_4(ss); while (ea < se - 24) { if (user_cancelled()) return found; iters = iters + 1; if ((iters % PROGRESS_EVERY) == 0) { msg("[brute-scan] 0x%x | achadas: %d\n", ea, g_stat_brute); } if (get_wide_dword(ea) == expected_sig) { auto cheap_ok = 1; if (g_is_64) { auto self_rva = get_wide_dword(ea + 0x14); if (rva_to_ea(self_rva) != ea) cheap_ok = 0; } if (cheap_ok && validate_col(ea)) { auto vt_found = 0; auto xv = get_first_dref_to(ea); while (xv != BADADDR) { auto vt = xv + g_ptr_size; if (is_valid_code_ptr(read_ptr(vt))) { if (analyze_vtable(vt) > 0) { vt_found = vt_found + 1; found = found + 1; g_stat_brute = g_stat_brute + 1; } } xv = get_next_dref_to(ea, xv); } if (vt_found == 0) { auto extra = brute_force_vt_for_col(ea); found = found + extra; g_stat_brute = g_stat_brute + extra; } } } ea = ea + 4; if ((ea & 0xFFFF) == 0) { } } } log_info("brute " + arch_label + ": " + ltoa(found, 10) + " novas vtables"); return found; } static brute_force_x64() { return brute_force_rtti(); } // ========================================================================= // PROPAGACAO DE OVERRIDES // // Para cada classe com pais, percorre o primeiro pai (ancestral imediato) // e compara slot a slot: // - Mesmo func ptr -> METODO HERDADO (apenas registra) // - Func ptr difere -> OVERRIDE (comenta no slot e na funcao) // // Tambem emite vtables_overrides.json com as relacoes encontradas. // ========================================================================= static emit_override_json(child_name, child_vt, slot_idx, parent_name, parent_func, child_func) { auto of = g_overrides_handle; if (of == 0) return; if (!g_overrides_first) fprintf(of, ",\n"); g_overrides_first = 0; fprintf(of, " {\"child\": \"%s\", \"slot\": %d, \"parent\": \"%s\", \"parent_func\": \"0x%x\", \"child_func\": \"0x%x\"}", child_name, slot_idx, parent_name, parent_func, child_func); } static first_parent_td(parents_csv) { if (parents_csv == "" || parents_csv == 0) return 0; auto pos = strstr(parents_csv, ","); auto first = (pos != -1) ? substr(parents_csv, 0, pos) : parents_csv; return atol(first); } static find_parent_td_for_offset(col_ea, target_offset) { if (target_offset == 0) return 0; auto chd = col_read_field(col_ea, 0x10); if (!is_valid_data_ptr(chd)) return 0; auto num_bases = get_wide_dword(chd + 0x08); if (num_bases <= 1 || num_bases > 64) return 0; auto bca_field = get_wide_dword(chd + 0x0C); auto bca_ea = g_is_64 ? rva_to_ea(bca_field) : bca_field; if (!is_valid_data_ptr(bca_ea)) return 0; auto i; for (i = 1; i < num_bases; i = i + 1) { auto bcd_field = get_wide_dword(bca_ea + i * 4); auto bcd_ea = g_is_64 ? rva_to_ea(bcd_field) : bcd_field; if (!is_valid_data_ptr(bcd_ea)) continue; auto mdisp = get_wide_dword(bcd_ea + 0x08); if (mdisp == target_offset) { auto td_field = get_wide_dword(bcd_ea); return g_is_64 ? rva_to_ea(td_field) : td_field; } } return 0; } // ========================================================================= // TOPOLOGICAL SORT (pais antes de filhos) // ========================================================================= static topo_dfs(vt_ea, count) { if (arr_get_long(ARR_TOPO_VISITED, vt_ea) > 0) return count; arr_set_long(ARR_TOPO_VISITED, vt_ea, 1); auto parents = hier_parents(vt_ea); auto buf = ""; auto i; auto n = strlen(parents); for (i = 0; i <= n; i = i + 1) { auto c = (i < n) ? substr(parents, i, i + 1) : ","; if (c == ",") { if (buf != "") { auto td = atol(buf); auto pvt = hier_vt_by_td(td); if (pvt != BADADDR) count = topo_dfs(pvt, count); } buf = ""; } else { buf = buf + c; } } arr_set_long(ARR_TOPO_ORDER, count, vt_ea); return count + 1; } static topo_build() { arr_init(ARR_TOPO_VISITED); arr_init(ARR_TOPO_ORDER); arr_init(ARR_TOPO_COUNT); auto count = 0; auto i; for (i = 0; i < g_vt_list_count; i = i + 1) { if (user_cancelled()) break; auto vt = hier_vt_at(i); if (vt != BADADDR) count = topo_dfs(vt, count); } arr_set_long(ARR_TOPO_COUNT, 0, count); log_info("Topological order: " + ltoa(count, 10) + " classes"); return count; } static topo_at(idx) { auto v = arr_get_long(ARR_TOPO_ORDER, idx); if (v == -1) return BADADDR; return v; } static topo_count() { auto v = arr_get_long(ARR_TOPO_COUNT, 0); if (v == -1) return 0; return v; } static propagate_overrides() { if (!PROPAGATE_OVERRIDES) return; if (g_vt_list_count == 0) return; auto tcount = topo_count(); if (tcount == 0) return; log_info("=== Passada de overrides em ordem topologica (" + ltoa(tcount, 10) + " classes) ==="); auto i; for (i = 0; i < tcount; i = i + 1) { if (user_cancelled()) return; auto vt_ea = topo_at(i); if (vt_ea == BADADDR) continue; auto parents_csv = hier_parents(vt_ea); if (parents_csv == "") continue; auto col_offset = hier_offset(vt_ea); auto parent_td; if (col_offset == 0) { parent_td = first_parent_td(parents_csv); } else { auto col_ea2 = hier_col(vt_ea); if (col_ea2 == BADADDR) continue; parent_td = find_parent_td_for_offset(col_ea2, col_offset); } if (parent_td == 0) continue; auto parent_vt = hier_vt_by_td(parent_td); if (parent_vt == BADADDR) { continue; } auto child_name = hier_name(vt_ea); auto parent_name = hier_name(parent_vt); auto own_count = hier_count(vt_ea); auto parent_count = hier_count(parent_vt); auto limit = (parent_count < own_count) ? parent_count : own_count; auto j; for (j = 0; j < limit; j = j + 1) { auto cslot = vt_ea + j * g_ptr_size; auto pslot = parent_vt + j * g_ptr_size; auto cfunc = read_ptr(cslot); auto pfunc = read_ptr(pslot); if (cfunc == pfunc) { g_stat_inherited = g_stat_inherited + 1; if (!DRY_RUN) { auto pname = get_func_name(pfunc); auto child_pattern = child_name + "__vmethod_" + ltoa(j, 10); if (pname == child_pattern) { auto canonical = parent_name + "__vmethod_" + ltoa(j, 10); if (set_name(pfunc, canonical, SN_NOWARN | SN_FORCE)) { g_stat_renamed_inherited = g_stat_renamed_inherited + 1; pname = canonical; } } set_cmt(cslot, sprintf("[%d] HERDADO de %s (-> %s)", j, parent_name, pname), 0); } } else { g_stat_overrides = g_stat_overrides + 1; if (!DRY_RUN) { auto pname2 = get_func_name(pfunc); set_cmt(cslot, sprintf("[%d] OVERRIDE de %s::%s", j, parent_name, pname2), 0); set_color(cslot, CIC_ITEM, COLOR_OVERRIDE); auto cfn = get_func_name(cfunc); auto rep = "Override de " + parent_name + "::" + pname2; auto existing = get_func_cmt(cfunc, 1); auto can_set_func_cmt = 0; if (existing == "" || existing == 0) can_set_func_cmt = 1; else if (starts_with(existing, "Override de ")) can_set_func_cmt = 1; if (can_set_func_cmt) set_func_cmt(cfunc, rep, 1); } emit_override_json(child_name, vt_ea, j, parent_name, pfunc, cfunc); } } } log_info("Overrides: " + ltoa(g_stat_overrides, 10) + " Herdados: " + ltoa(g_stat_inherited, 10)); } // ========================================================================= // MAIN // ========================================================================= static main() { if (CLEAR_OUTPUT_ON_START) { process_ui_action("msglist:Clear", 0); } msg("\n========================================\n"); msg("Vtable Analyzer Pro v5.3 - iniciando...\n"); msg("========================================\n"); if (REGISTER_HOTKEY) { add_idc_hotkey(HOTKEY_COMBO, "main"); msg("[INFO] Hotkey %s registrada para re-rodar o script\n", HOTKEY_COMBO); } g_is_64 = (get_inf_attr(INF_LFLAGS) & LFLG_64BIT) ? 1 : 0; g_ptr_size = g_is_64 ? 8 : 4; g_imagebase = get_imagebase(); g_json_first = 1; g_overrides_first = 1; g_vt_list_count = 0; g_stat_classes = 0; g_stat_methods = 0; g_stat_renamed = 0; g_stat_ctors = 0; g_stat_dtors = 0; g_stat_pures = 0; g_stat_overrides = 0; g_stat_inherited = 0; g_stat_brute = 0; g_stat_thiscall = 0; g_stat_sizes = 0; g_stat_singletons = 0; g_stat_vcalls = 0; g_stat_header_classes = 0; g_stat_renamed_inherited = 0; g_purecall_csv = ""; g_stat_filtered = 0; g_stat_errors = 0; auto out_dir = resolve_output_dir(); auto json_path = path_join(out_dir, OUTPUT_JSON_NAME); auto log_path = path_join(out_dir, OUTPUT_LOG_NAME); auto overrides_path = path_join(out_dir, OUTPUT_OVERRIDES_NAME); auto header_path = path_join(out_dir, OUTPUT_HEADER_NAME); msg("[INFO] Pasta de saida: %s\n", out_dir); msg("[INFO] JSON esperado em: %s\n", json_path); msg("[INFO] LOG esperado em: %s\n", log_path); msg("[INFO] OVERRIDES esperado em: %s\n", overrides_path); msg("[INFO] HEADER esperado em: %s\n", header_path); g_log_handle = safe_fopen(log_path, "w"); if (g_log_handle == 0) { msg("[WARN] Log em arquivo desabilitado, continuando so com console.\n"); } log_info("===================================================="); log_info(" Vtable Analyzer Pro v5.3 - IDA Free 9.x"); log_info("===================================================="); log_info("Arquitetura : " + (g_is_64 ? "x64" : "x86")); log_info("Ptr size : " + ltoa(g_ptr_size, 10)); log_info("Image base : 0x" + ltoa(g_imagebase, 16)); log_info("Pasta saida : " + out_dir); log_info("Dry run : " + (DRY_RUN ? "SIM" : "NAO")); log_info("Cria struct : " + (CREATE_STRUCTS ? "SIM" : "NAO")); log_info("Sobrescreve : " + (RENAME_OVERRIDES ? "SIM" : "NAO")); log_info("Ponteiro-scan: " + (POINTER_FIRST_SCAN ? "SIM" : "NAO")); log_info("String-scan : " + (STRING_FIRST_SCAN ? "SIM" : "NAO")); log_info("Overrides : " + (PROPAGATE_OVERRIDES ? "SIM" : "NAO")); log_info("Brute x64 : " + (BRUTE_FORCE_X64_RVA ? "SIM" : "NAO") + (g_is_64 ? "" : " (inerte em x86)")); log_info("Brute x86 : " + (BRUTE_FORCE_X86 ? "SIM" : "NAO") + (g_is_64 ? " (inerte em x64)" : "")); log_info("__thiscall : " + (APPLY_THISCALL_TYPES ? "SIM" : "NAO")); log_info("Sizeof obj : " + (DETECT_OBJECT_SIZES ? "SIM" : "NAO")); log_info("Singletons : " + (DETECT_SINGLETONS ? "SIM" : "NAO")); log_info("VCall annotat: " + (ANNOTATE_VCALLS ? "SIM" : "NAO")); log_info("CPP header : " + (EMIT_CPP_HEADER ? "SIM" : "NAO")); log_info("Excl framewrk: " + (EXCLUDE_FRAMEWORK_CLASSES ? "SIM" : "NAO")); log_info("Size inferenc: " + (SIZE_INFER_FROM_BODY ? "SIM" : "NAO")); log_info("Singl agressv: " + (SINGLETON_AGGRESSIVE ? "SIM" : "NAO")); cache_init(); init_purecall_addresses(); if (g_purecall_csv != "") { log_info("purecall enderecos conhecidos: " + g_purecall_csv); } g_json_handle = safe_fopen(json_path, "w"); if (g_json_handle != 0) { fprintf(g_json_handle, "{\n"); fprintf(g_json_handle, " \"meta\": {\n"); fprintf(g_json_handle, " \"arch\": \"%s\",\n", g_is_64 ? "x64" : "x86"); fprintf(g_json_handle, " \"ptr_size\": %d,\n", g_ptr_size); fprintf(g_json_handle, " \"imagebase\": \"0x%x\",\n", g_imagebase); fprintf(g_json_handle, " \"tool\": \"vtable_analyzer_pro_v5.2\",\n"); fprintf(g_json_handle, " \"stats_note\": \"methods=total slots; pures/inherited/overrides sao subconjuntos disjuntos de methods\"\n"); fprintf(g_json_handle, " },\n"); fprintf(g_json_handle, " \"classes\": [\n"); } g_overrides_handle = safe_fopen(overrides_path, "w"); if (g_overrides_handle != 0) { fprintf(g_overrides_handle, "{\n \"overrides\": [\n"); } if (POINTER_FIRST_SCAN) scan_via_pointers(); if (STRING_FIRST_SCAN) scan_via_rtti_strings(); if ((g_is_64 && BRUTE_FORCE_X64_RVA) || (!g_is_64 && BRUTE_FORCE_X86)) brute_force_rtti(); topo_build(); propagate_overrides(); apply_all_thiscall_types(); annotate_virtual_calls(); emit_cpp_header(header_path); if (g_json_handle != 0) { fprintf(g_json_handle, "\n ],\n"); fprintf(g_json_handle, " \"stats\": {\n"); fprintf(g_json_handle, " \"classes\": %d,\n", g_stat_classes); fprintf(g_json_handle, " \"methods\": %d,\n", g_stat_methods); fprintf(g_json_handle, " \"renamed\": %d,\n", g_stat_renamed); fprintf(g_json_handle, " \"ctors\": %d,\n", g_stat_ctors); fprintf(g_json_handle, " \"dtors\": %d,\n", g_stat_dtors); fprintf(g_json_handle, " \"pures\": %d,\n", g_stat_pures); fprintf(g_json_handle, " \"overrides\": %d,\n", g_stat_overrides); fprintf(g_json_handle, " \"inherited\": %d,\n", g_stat_inherited); fprintf(g_json_handle, " \"brute_x64\": %d,\n", g_stat_brute); fprintf(g_json_handle, " \"thiscall\": %d,\n", g_stat_thiscall); fprintf(g_json_handle, " \"sizes\": %d,\n", g_stat_sizes); fprintf(g_json_handle, " \"singletons\":%d,\n", g_stat_singletons); fprintf(g_json_handle, " \"vcalls\": %d,\n", g_stat_vcalls); fprintf(g_json_handle, " \"hdr_class\": %d,\n", g_stat_header_classes); fprintf(g_json_handle, " \"renamed_inherited\": %d,\n", g_stat_renamed_inherited); fprintf(g_json_handle, " \"methods_concrete\": %d,\n", g_stat_methods - g_stat_pures); fprintf(g_json_handle, " \"filtered\": %d,\n", g_stat_filtered); fprintf(g_json_handle, " \"errors\": %d\n", g_stat_errors); fprintf(g_json_handle, " }\n}\n"); fclose(g_json_handle); } if (g_overrides_handle != 0) { fprintf(g_overrides_handle, "\n ]\n}\n"); fclose(g_overrides_handle); } log_info("===================================================="); log_info(" RESUMO"); log_info(" Classes encontradas : " + ltoa(g_stat_classes, 10)); log_info(" Metodos virtuais : " + ltoa(g_stat_methods, 10)); log_info(" Funcoes renomeadas : " + ltoa(g_stat_renamed, 10)); log_info(" Construtores : " + ltoa(g_stat_ctors, 10)); log_info(" Destrutores : " + ltoa(g_stat_dtors, 10)); log_info(" Purecalls : " + ltoa(g_stat_pures, 10)); log_info(" Overrides marcados : " + ltoa(g_stat_overrides, 10)); log_info(" Metodos herdados : " + ltoa(g_stat_inherited, 10)); log_info(" Brute x64 : " + ltoa(g_stat_brute, 10)); log_info(" __thiscall : " + ltoa(g_stat_thiscall, 10)); log_info(" Sizes detectados : " + ltoa(g_stat_sizes, 10)); log_info(" Singletons : " + ltoa(g_stat_singletons, 10)); log_info(" VCall sites : " + ltoa(g_stat_vcalls, 10)); log_info(" Classes no header : " + ltoa(g_stat_header_classes, 10)); log_info(" Renorm. herdados : " + ltoa(g_stat_renamed_inherited, 10)); log_info(" Metodos concretos : " + ltoa(g_stat_methods - g_stat_pures, 10)); log_info(" Filtradas (framework): " + ltoa(g_stat_filtered, 10)); log_info(" Erros : " + ltoa(g_stat_errors, 10)); log_info("===================================================="); log_info("JSON : " + json_path); log_info("OVERRIDES : " + overrides_path); log_info("HEADER : " + header_path); log_info("LOG : " + log_path); log_info(""); log_info("=== ARQUIVOS GERADOS ==="); auto check_h; check_h = fopen(json_path, "r"); if (check_h != 0) { fseek(check_h, 0, 2); log_info(sprintf(" JSON : %d bytes", ftell(check_h))); fclose(check_h); } else { log_info(" JSON : NAO GERADO"); } check_h = fopen(overrides_path, "r"); if (check_h != 0) { fseek(check_h, 0, 2); log_info(sprintf(" OVERRIDES : %d bytes", ftell(check_h))); fclose(check_h); } else { log_info(" OVERRIDES : NAO GERADO"); } check_h = fopen(header_path, "r"); if (check_h != 0) { fseek(check_h, 0, 2); log_info(sprintf(" HEADER : %d bytes", ftell(check_h))); fclose(check_h); } else { log_info(" HEADER : NAO GERADO"); } if (g_log_handle != 0) fclose(g_log_handle); msg("\n=== Vtable Analyzer Pro v5.3 finalizado ===\n"); msg("Classes=%d Metodos=%d Renomeadas=%d Ctors=%d Dtors=%d Pures=%d Overrides=%d\n", g_stat_classes, g_stat_methods, g_stat_renamed, g_stat_ctors, g_stat_dtors, g_stat_pures, g_stat_overrides); msg("ThisCall=%d Sizes=%d Singletons=%d VCalls=%d HdrClasses=%d\n", g_stat_thiscall, g_stat_sizes, g_stat_singletons, g_stat_vcalls, g_stat_header_classes); }
    8 pontos
  2. ⚔️WYD INFINITY ⚔️ 📅 Inaugurado dia: 01/05/2026 às 13h 📌 Informações Gerais Versão: 7.89 Dificuldade: Easy / Medium UP Rápido: Mortal/Arch UP Celestial: Easy até 200/200 - 200+ Medium Contas por IP: (5) 🔥 "O Farm te prepara. O PVP te define." 📌 Sistemas Guerras de Guilds Arena Real Pesadelo celestial liberado Dominação de Bosses com espólios valiosos Droplist com filtro de drop Sistema de Honra Valioso e Diferenciado Sistema Guerra entre Reinos Player Info Ranking atualizado Sistema de Balanceamento PVP e PVE Baú de carga com 4 slots Resoluções Widescreen sem distorções Loja desvinculada: Progrida livremente Loja de Donate: Acesse de qualquer lugar Novidades de NPCs: recicladores e compositores Novos slots: colar, cinto, traje montaria Sistema Revigorante (proteção de montaria) Fada Dourada: agrupador de itens, filtro e macro de água Auto Grupo Anti-Hack · Anti-DDoS Servidor Estável 24/7 Entre outros... 🌐Redes Sociais 🌍 Site: [Hidden Content] 💬 Discord: [Hidden Content] 📸 Instagram: [Hidden Content] 📱 WhatsApp: [Hidden Content] 🌐Download: Download do Cliente : DOWNLOAD DO CLIENT Scan CLIENT Scan EXE Administrador por: G2K 📌 Imagens sobre o WYD INFINITY Campo iniciante de ARMIA: Sistemas: Painéis no servidor: NPC'S (Se compra em gold e itens)(Ambos são FARM) VALE ESCONDIDO (CONTÉM 3 ANDARES) CAPAS CELESTIAIS
    5 pontos
  3. Só funcionará com servidores que não tem proteção para o Cheat Engine COMENTE O POST E CLIQUE NO BOTÃO DE LIKE PARA LIBERAR OS CHEATS Primeiramente faça o download do Cheat Engine: [Hidden Content] One Hit [Hidden Content] HP Hack [Hidden Content] MP Hack [Hidden Content] Speed Hack [Hidden Content] Stage Hack [Hidden Content] Créditos: ---Tinho---
    4 pontos
  4. /* Estilos CSS adaptados para a cor exata do fórum (#272626) */ .gh-topic-container { font-family: 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif; background-color: #272626; /* Cor exata solicitada */ color: #eeeeee; padding: 30px; border-radius: 10px; margin: 20px auto; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3); border: 1px solid #363535; /* Borda sutil levemente mais clara que o fundo */ } /* ---- Estilos do Banner ---- */ .gh-banner-wrapper { width: 100%; margin-bottom: 35px; border-radius: 12px; overflow: hidden; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); border-bottom: 3px solid #8b5cf6; } .gh-banner-img { width: 100%; height: auto; display: block; transition: transform 0.5s ease; } .gh-banner-wrapper:hover .gh-banner-img { transform: scale(1.01); } /* ---- Tipografia e Conteúdo ---- */ .gh-main-title { font-size: 2.8rem; font-weight: 900; text-transform: uppercase; margin-bottom: 0px; text-align: center; letter-spacing: -1px; color: #ffffff; } .gh-highlight-purple { color: #a855f7; text-shadow: 0 0 10px rgba(168, 85, 247, 0.4); } .gh-subtitle-topic { font-size: 1.3rem; color: #bbbbbb; text-align: center; margin-bottom: 40px; font-weight: 300; border-bottom: 1px solid #363535; } /* Caixa de Destaque Positiva (Ajustada para o fundo #272626) */ .gh-feature-box { background: #1e2920; /* Tom verde escuro fechado para contrastar com o grafite */ border: 1px solid rgba(34, 197, 94, 0.2); border-left: 5px solid #22c55e; padding: 25px; border-radius: 8px; margin-bottom: 25px; } .gh-feature-title { font-size: 1.4rem; color: #4ade80; font-weight: bold; margin-bottom: 12px; display: flex; align-items: center; } .gh-feature-title::before { content: '✓'; margin-right: 10px; font-weight: 900; } .gh-text-content { font-size: 1.05rem; line-height: 1.6; color: #e0e0e0; margin-bottom: 20px; } /* ---- Botão estilo o "Desbloquear" do print ---- */ .gh-button-container { text-align: center; margin: 0px 30px 30px 30px; } .gh-cta-button { background: linear-gradient(to right, #8b5cf6, #6366f1); /* Roxo vibrante idêntico à imagem */ color: white !important; padding: 16px 45px; text-decoration: none; font-size: 1.15rem; font-weight: 700; border-radius: 8px; transition: all 0.2s ease; display: inline-block; text-transform: uppercase; border: none; cursor: pointer; box-shadow: 0 5px 20px rgba(139, 92, 246, 0.4); } .gh-cta-button:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(139, 92, 246, 0.6); filter: brightness(1.1); } .gh-footer-topic { text-align: center; font-size: 0.85rem; color: #888888; margin-top: 40px; } .gh-footer-topic a { color: #a855f7; text-decoration: none; } /* ---- Caixa Alerta (Ajustada para o fundo #272626) ---- */ .gh-virustotal-box { background: #2d1919; /* Tom avermelhado escuro para contrastar com o grafite */ border: 1px solid rgba(239, 68, 68, 0.2); border-left: 5px solid #ef4444; padding: 25px; margin: 25px 0; border-radius: 8px; } .gh-virustotal-title { font-size: 1.4rem; color: #f87171; font-weight: bold; margin-bottom: 12px; } canva pro LINK DE CONVITE CANVA PRO Manter este projeto ativo tem custos. Se você gostar da experiência e quiser mais estabilidade, suporte 24h e um perfil exclusivo para você, considere apoiar o projeto adquirindo uma assinatura a partir de R$ 1,90. Sua Conta Privada Acesso completo por 30 dias com perfil exclusivo e tela privada — apenas você assiste, sem limites ou interrupções. Seu histórico fica organizado e protegido, sem interferências. Entrega automática em segundos via PIX, com suporte garantido via chat. ❌ Conta Compartilhada Compartilhada com dezenas de pessoas, sem tela privada — outros usuários veem seu histórico e o que você assiste. Limite de telas excedido frequentemente, causando interrupções. Senha alterada periodicamente, tornando o acesso temporário e instável. Perfis bagunçados e histórico misturado, gerando recomendações erradas baseadas no consumo de terceiros. Perfis genéricos, sem personalização de nome ou foto. Sem suporte ou garantia em caso de problemas. Mais de 80% dos membros do fórum começaram testando as contas gratuitas e migraram para o plano privado. Garanta sua estabilidade hoje mesmo! Quero minha Conta Privada agora
    3 pontos
  5. /* Estilos CSS adaptados para a cor exata do fórum (#272626) */ .gh-topic-container { font-family: 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif; background-color: #272626; /* Cor exata solicitada */ color: #eeeeee; padding: 30px; border-radius: 10px; margin: 20px auto; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3); border: 1px solid #363535; /* Borda sutil levemente mais clara que o fundo */ } /* ---- Estilos do Banner ---- */ .gh-banner-wrapper { width: 100%; margin-bottom: 35px; border-radius: 12px; overflow: hidden; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); border-bottom: 3px solid #8b5cf6; } .gh-banner-img { width: 100%; height: auto; display: block; transition: transform 0.5s ease; } .gh-banner-wrapper:hover .gh-banner-img { transform: scale(1.01); } /* ---- Tipografia e Conteúdo ---- */ .gh-main-title { font-size: 2.8rem; font-weight: 900; text-transform: uppercase; margin-bottom: 0px; text-align: center; letter-spacing: -1px; color: #ffffff; } .gh-highlight-purple { color: #a855f7; text-shadow: 0 0 10px rgba(168, 85, 247, 0.4); } .gh-subtitle-topic { font-size: 1.3rem; color: #bbbbbb; text-align: center; margin-bottom: 40px; font-weight: 300; border-bottom: 1px solid #363535; } /* Caixa de Destaque Positiva (Ajustada para o fundo #272626) */ .gh-feature-box { background: #1e2920; /* Tom verde escuro fechado para contrastar com o grafite */ border: 1px solid rgba(34, 197, 94, 0.2); border-left: 5px solid #22c55e; padding: 25px; border-radius: 8px; margin-bottom: 25px; } .gh-feature-title { font-size: 1.4rem; color: #4ade80; font-weight: bold; margin-bottom: 12px; display: flex; align-items: center; } .gh-feature-title::before { content: '✓'; margin-right: 10px; font-weight: 900; } .gh-text-content { font-size: 1.05rem; line-height: 1.6; color: #e0e0e0; margin-bottom: 20px; } /* ---- Botão estilo o "Desbloquear" do print ---- */ .gh-button-container { text-align: center; margin: 0px 30px 30px 30px; } .gh-cta-button { background: linear-gradient(to right, #8b5cf6, #6366f1); /* Roxo vibrante idêntico à imagem */ color: white !important; padding: 16px 45px; text-decoration: none; font-size: 1.15rem; font-weight: 700; border-radius: 8px; transition: all 0.2s ease; display: inline-block; text-transform: uppercase; border: none; cursor: pointer; box-shadow: 0 5px 20px rgba(139, 92, 246, 0.4); } .gh-cta-button:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(139, 92, 246, 0.6); filter: brightness(1.1); } .gh-footer-topic { text-align: center; font-size: 0.85rem; color: #888888; margin-top: 40px; } .gh-footer-topic a { color: #a855f7; text-decoration: none; } /* ---- Caixa Alerta (Ajustada para o fundo #272626) ---- */ .gh-virustotal-box { background: #2d1919; /* Tom avermelhado escuro para contrastar com o grafite */ border: 1px solid rgba(239, 68, 68, 0.2); border-left: 5px solid #ef4444; padding: 25px; margin: 25px 0; border-radius: 8px; } .gh-virustotal-title { font-size: 1.4rem; color: #f87171; font-weight: bold; margin-bottom: 12px; } PRIME VÍDEO ACESSAR DADOS DA CONTA Crunchyroll ACESSAR DADOS DA CONTA paramount ACESSAR DADOS DA CONTA Manter este projeto ativo tem custos. Se você gostar da experiência e quiser mais estabilidade, suporte 24h e um perfil exclusivo para você, considere apoiar o projeto adquirindo uma assinatura a partir de R$ 1,90. Sua Conta Privada Acesso completo por 30 dias com perfil exclusivo e tela privada — apenas você assiste, sem limites ou interrupções. Seu histórico fica organizado e protegido, sem interferências. Entrega automática em segundos via PIX, com suporte garantido via chat. ❌ Conta Compartilhada Compartilhada com dezenas de pessoas, sem tela privada — outros usuários veem seu histórico e o que você assiste. Limite de telas excedido frequentemente, causando interrupções. Senha alterada periodicamente, tornando o acesso temporário e instável. Perfis bagunçados e histórico misturado, gerando recomendações erradas baseadas no consumo de terceiros. Perfis genéricos, sem personalização de nome ou foto. Sem suporte ou garantia em caso de problemas. Mais de 80% dos membros do fórum começaram testando as contas gratuitas e migraram para o plano privado. Garanta sua estabilidade hoje mesmo! Quero minha Conta Privada agora
    3 pontos
  6. ASSINATURAS ATUALIZADAS Patrocinadora: streamingsbarato.com [Hidden Content] [Hidden Content] [Hidden Content] [Hidden Content] Assinatura será atualizada todos os meses.
    3 pontos
  7. 100% ATUALIZADO(2026) INTRODUÇÃO A Fox com muito orgulho apresenta seu produto para Grand Chase Classic (Steam/Nexus/Megaxus/Epic Games/etc) Acesse nosso site e tenha acesso à mais produtos exclusivos: Forums - Fox Cheats FUNÇÕES 🎯 Categoria: Mission Hack Auto Kill Delay — Mata todos os mobs da missão automaticamente. Skip Dialog — Pula todos os diálogos possíveis durante a missão. Kill All — Usado junto com o Auto Kill Delay para matar mobs que suportam o sistema. Stealth — Faz com que os mobs não ataquem você. Monster Vac — Agrupa todos os mobs hostis em um único local. Item Vac — Coleta automaticamente todos os itens dropados. Item Hide — Esconde todos os itens da missão para melhor visualização. Auto Boss — Avança automaticamente para a Boss Fight quando disponível. Unlimited Dimensional Time — Permite ficar mais de 15 minutos no portão dimensional. Level Hack [VOID] — Permite jogar o VOID sem precisar ser level 85. Item Spawn — Dropa todos os itens que seriam obtidos na missão. Speed Farm — Carrega uma missão alternativa para acelerar o farm. Damage Mob — Multiplicador de dano que você sofrerá dos mobs. Damage Hack — Aumenta o dano que você causa aos mobs. Auto Portal — Passa as etapas automaticamente sem interação manual. Speed Hack — Acelera a velocidade do jogo. Super Talim Spam — Spama o ataque especial do evento de Talin em qualquer missão. 🏆 Categoria: Mission Result Rank Select — Escolha a pontuação de rank da missão (F até SS). Hits Count — Quantidade de hits que você causou na missão. Combo Count — Número total de combos realizados. Attack Back Count — Número de ataques realizados pelas costas dos inimigos. Hits Takken — Quantidade de hits que você sofreu durante a missão. Damage Count — Total de dano que você causou na missão. 👤 Categoria: Player Stats HP Infinity — Vida infinita para o seu personagem. MP Full — Mana infinita para usar habilidades sem restrição. Hide Nick — Esconde seu nick no jogo [STREAM MODE]. Potion CD — Remove o cooldown para usar poções sem tempo de espera. CoolDown Hack — Remove o cooldown das skills, podendo usar sem limite. Fly Hack — Permite que seu personagem voe livremente. Pet MP — Mana infinita para o seu Pet. Furia Full — Fúria sempre cheia para usar golpes especiais. Item Hack [N] — Permite usar itens do inventário [N] sem possuí-los. Status SS — Aumenta seus atributos para atingir status SS+ e completar eventos/missões especiais. 🤖 Categoria: Bots/Farming Drop Prediction — Permite visualizar os itens que irão dropar dos mobs na missão. Block Dialog — Bloqueia janelas de diálogo para farmar AFK. Anti Kick AFK — Impede o jogo de te expulsar por ficar AFK. Auto Start — Inicia automaticamente as missões. Auto Next Dungeon — Avança automaticamente para a próxima missão. Auto Ready — Confirma "Pronto" automaticamente nas missões. Auto Play Dungeon — Joga automaticamente a missão selecionada. Auto Farm Item — Farma repetidamente o item adicionado na lista. Auto Failed — Faz a missão falhar automaticamente. Auto Farm Cards — Farma cartas automaticamente na missão. 🎮 Categoria: Auto Collect And Quit Collect And Quit — Entra na missão que você desejar, coleta os itens desejado e quita (FARM AUTOMATICO DE ITENS 100% AFK E RAPIDO 🎮 Categoria: AUTO VOID 100% AFK 23 CHAR AUTO VOID 100% AFK 23 CHAR — Entra na missão do void desejada, completa automaticamente com todos os personagens desejados e para (100% AFK) ENTREGA AUTOMÁTICA COMPRE AQUI OU NO SITE: [Hidden Content] SCREEN SHOTS PREÇOS 30 Dias -> R$39,90 ONDE COMPRAR ? Nosso Site -> Forums - Fox Cheats Nosso Discord : [Hidden Content] COMO USAR Abra o cheat Abra o jogo Seja feliz! DOWNLOAD/SCAN DOWNLOAD x64 : [Hidden Content] SCAN x64 : VirusTotal - File - 4851f472de5f1be722f62b62c1da749723ca086eddda36347db9996da39a0850
    2 pontos
  8. Tutorial 🔰 Passo 1 — Abrir o Loader: Clique com o botão direito no Loader e selecione “Executar como administrador”. 🔰 Passo 2 — Login: Digite seu usuário e senha cadastrados no site FRCHEATS para acessar o painel do Loader. 🔰 Passo 3 — Escolha do Jogo: Selecione o jogo que deseja usar o cheat: CrossFire BR ou CrossFire West. Clique em Injetar Cheat WALLHACK É AUTO ON Atenção Sabemos que ao baixar ou executar nosso Loader (FRLOADER) alguns antivírus podem exibir alertas como "Trojan", "Malware" ou "Aplicativo Potencialmente Indesejado (PUA)". Queremos tranquilizar todos: o nosso loader não é um vírus, trojan ou ameaça real. Essa detecção acontece porque o Loader realiza operações que são comuns também em ferramentas maliciosas, como: Comunicação com servidor remoto (para autenticação do token) Criação e leitura de arquivos locais Download e execução de arquivos compactados (cheats) Injeção de código na memória do jogo (para o funcionamento do cheat) Esses comportamentos são essenciais para que o Loader funcione, mas também são parecidos com os de alguns malwares — por isso alguns antivírus marcam o loader como suspeito por padrão, mesmo sem nenhuma ameaça real. Download/Scanner [Hidden Content]
    2 pontos
  9. Essas Contas Da Unitv Tem Vip Ativo Até as Datas Descritas Abaixo De Cada Conta Unitv é um Serviço De Iptv Com 490 Canais, Área Para Jogos De Futebol, Filmes,Séries,Animes,Novelas e Conteúdo Adulto, Pode Ser Usado Em Celulares Android, Tv Android e Tv Box [Hidden Content]
    2 pontos
  10. Olá, Desenvolvi esse cheat para os servidores Fatal Chase e Chase Heroes. Para usuários que se cadastrarem e não adquirirem um plano a única opção no momento é o Bypass e One Hit e para o Chase Heroes MP Hack. Funções: [Hidden Content] Discord: JCheats
    2 pontos
  11. 🚨 ATENÇÃO, JOGADORES DE WYD! O STAR DESTINY ESTÁ VOLTANDO! 🚨 A espera está chegando ao fim… o lendário With Your Destiny – STAR DESTINY (Base 2011 a 2018) está em processo de reabertura oficial! 🔥 E dessa vez, vem com tudo: ✅ Nova administração – mais comprometida, organizada e focada na comunidade ✅ Marca STAR DESTINY registrada – segurança e seriedade no projeto ✅ Servidor pensado para durar – com responsabilidade de manter online e estável 💭 A proposta é clara: trazer de volta a nostalgia pura dos tempos de ouro, entre 2011 e 2018, com aquele estilo clássico que marcou gerações! ⚔️ PvP raiz 🏰 Guerras épicas 💎 Farm na raça 👥 Comunidade unida como antigamente Se você sente saudade dessa época, essa é a sua chance de reviver tudo isso novamente! 📢 Acompanhe a página oficial e fique por dentro de todas as novidades: 👉 [Hidden Content] 🔥 STAR DESTINY ESTÁ DE VOLTA — E DESSA VEZ, PARA FICAR! Atendimento ao jogadores (18)99813-2256
    2 pontos
  12. Cansado de mapa genérico? Cansado de depender de editor bugado? 👉 Então presta atenção nisso aqui. Estou liberando um Editor de Mapas WYD COMPLETO, feito pra quem quer dominar o servidor de verdade. 💣 O QUE VOCÊ CONSEGUE FAZER ✔ Montar cidades, dungeons, eventos exclusivos ✔ Controlar terreno, relevo e objetos com precisão ✔ Trabalhar com velocidade (sem travar, sem dor de cabeça) ⚡ DIFERENCIAL (E AQUI MUDA O JOGO) ✔ Interface direta (abriu, usou) ✔ Leve e rápido (roda liso) ✔ Estável (sem crash aleatório) ✔ Pensado pra WYD (não é gambiarra adaptada) 👉 Isso aqui não é editor meia boca. 🧠 PRA QUEM É ISSO? Donos de servidor que querem SE DESTACAR Devs que cansaram de ferramenta limitada Quem quer parar de copiar mapa dos outros 🚨 REALIDADE Servidor com mapa padrão = mais do mesmo Servidor com mapa custom = destaque 👉 Simples assim. 📸 PREVIEW [Hidden Content] 💰 VALOR 💲 Chama no privado / Discord 💥 Preço justo pelo que entrega (Pode rolar desconto pra primeiros) 📩 CONTATO 📬 Discord: .leowt 📬 PM no fórum ⚠️ AVISO ✔ Ferramenta exclusiva ✔ Suporte incluso ✔ Não é free 🔒 RESUMO Quer servidor comum → continua como tá Quer algo diferente → isso aqui resolve 🚀 GARANTA ANTES QUE GERAL COMECE A USAR Depois que começar a aparecer mapa diferente por aí… você já sabe de onde veio.
    2 pontos
  13. @ Grego Comprei uma conta disney em [Hidden Content] por conta deste post, e agora fica pedindo o código para confirmar a tela ou se estou fora de casa, já tem uma semana suporte n responde, nem email, nem whatsapp, usei o serviço apenas uma vez... Não recomendo. [edit] Comentei no discord da wc falando do problema, e me fizeram o reembolso.
    2 pontos
  14. LINK ATUALIZADO 15/04/2026: [Hidden Content] PATROCINADORA streamingsbarato.com Diversos Serviços streamings com 70% OFF
    2 pontos
  15. LINK ATUALIZADO 02/04/2026: [Hidden Content] PATROCINADORA streamingsbarato.com Diversos Serviços streamings com 70% OFF
    2 pontos
  16. Sejam MUITO BEM-VINDOS ao FatalChase Chaos [BETA]! Depois de muita espera, finalmente estamos no ar! Considerando que estamos em uma fase de testes, é totalmente esperado que haja alguns bugs esquisitos que podem E DEVEM ser reportados via Discord ou WhatsApp! Se quiser tirar dúvidas comuns, acesse a seção FAQ em nosso site [Hidden Content] Season Chaos Experiência intensificada com mais conteúdo. EXP/GP 5x Elesis a Mari 4ª, Dio a Rey 2ª, Lupus 4ª Mais conteúdo! Até 1500 VP Grátis por semana Site: [hide][Hidden Content]] Discord: [hide][Hidden Content]] Season Chaos [BETA] Mais conteudo, mais possibilidades de build e desafios repensados para manter a progressao intensa sem perder o DNA do jogo Tamanho: 2,36 GB
    2 pontos
  17. 🚀 STATUS DO SERVER ( ON! ) 🟢 PING LISO: 4ms (Radmin) ⚔️- 🔥👑[Chase Heroes]👑🔥 -⚔️ Tokens ❤️ Token: INICIANTEHEROES Token: HARKYON-KIT-FREE Token: SUPORTE-INICIANTE Token: KitPergaMistico 🔹 OBRIGATORIO – ENTRAR NA REDE DO RADMIN VPN Ja vem baixado no instalador! No Radmin VPN, clique em: Rede → Ingressar em uma rede existente Escolha apenas uma das redes abaixo: Nome da rede: grandchaselospikas Senha: 123456789 Nome da rede: gclospikas Senha: 123456789 Nome da rede: grand.pika Senha: 123456789 Clique em Entrar Tutorial completo a baixo. do download Disponível: Windows 7, Windows 10 e WINDOWS 11 Requisitos: minimo 4gb ram e win 7 Vai c/ Pacote Essenciais: Net 10, direct x e Microsoft C++ e Driver Booster 13 + Crack e Radmin com - Instalador Facilitado. www.youtube.com/watch?v=Q7qDnRnrMWs 😤 Cansado de farmar parecendo um mendigo? 😾 Ou jogar com pet inútil que não dá dano nenhum? 💸 Cansado de colocar dinheiro na KOG e receber zero consideração? 🌎 Nem valorizam nossa moeda — mesmo sendo a maior parte do servidor. 🔥 Foi por isso que este servidor nasceu. Feito para quem vive de salário mínimo. ❤️ Para quem ama Grand Chase, mas cansou de pagar caro por promessas vazias, 🚫 Aqui não tem investidor. Não tem empresa por trás, muita coisa ainda sai do meu bolso. ⭐ O VIP existe por um único motivo: Apena Manter o Servidor online e trazer Atualização. ❌ Não é sobre lucro. ✅ É sobre respeito ao jogador e a Historia de Grand Chase, Quem jogou Dede o Beta sabe oq eu estou falando, 💭 Se isso fez sentido pra você… talvez valha a pena conhecer mais. INVENTARIO e PET COMPARTILHADO A COMPRA DE CASH È AUTOMATICA DIRETO NO LAUNCHER QRCODE PIX Pagou? Cash caiu na conta de forma Automatica <3 Novos Pets Free To Play Coleção de Herois BUFFADA! Free tbm consegue jogar tranquilo COMO BAIXAR? 📌 Discord: [Hidden Content] 📌 Link do Blog: [Hidden Content] 📌 Link do youtube: [Hidden Content] 🛡️ VAMOS REERGUER ESSA LENDA JUNTOS! 🛡️
    1 ponto
  18. Link:⁨ Clique Aqui começa com 5 créditos iniciais, tem para vários sites
    1 ponto
  19. Equipe Infinity apresenta: Infinity Wyd 7.59 - LANÇAMENTO 01/05 as 19h -- OPEN BETA ROLANDO , CRIE SUA CONTA E VEM VER --- Cansado de Jogar de servidor em servidor? Cansado de injustiças por parte da administração que beneficia jogadores? Esse é o servidor para você! Pensado na experiencia de jogador para jogador, de quem jogou no antigo Wyd da Ongame e queria que a história continuasse. Temos poucos sistemas a mais de diferentes para o antigo Wyd, como nosso filtro de drop, sistema de ganho de honra por lojinha ativa a cada 5 minutos para trocar por itens básicos. Todos terão acesso e tentaremos oferecer o servidor com menor "Pay to Win" possível. Vem com a gente e dá uma chance a nostaliga! Versão: 7.59 EXP: Easy/Medio Drop: Easy/Medio Conexão: 24/7 Rates Compositores: 41% Para mais informações, acesse: Site : [Hidden Content] Discord : [Hidden Content] Facebook : [Hidden Content] Whatsapp : [Hidden Content] SERVIDOR PRÓPRIO COM LINK DEDICADO Sistemas exclusivos 📌 Ataque Mágico Azul. 📌 Modo Widescreen 📌 Jogo ira possuir 18 slots. Traje Montaria, Cinto, Colar 📌 As Fadas Azul e Vermelha estarão agrupando os itens agrupaveis. 📌 Colocando Lojinha por 5 minutos receba 1 Pontos de Honra. 📌 Comandos de Armia,Azran,Erion ETC. = Tecla D 📌 Loja donate in game = Tecla D 📌 Drop List in game = Tecla D Guerras 🛡️ Guerra de Cidade 21hr 🛡️ Guerra de Torres 22hr 🛡️ Guerra entre Reinos 20hr - 00hr 🛡️ Boss Dark Shadow a cada 4 horas DATA DE LANÇAMENTO 01/05 as 19h - CLIENTE SERÁ LIBERADO PRÓXIMO A ESSA DATA! PRÉ CADASTRO DISPONÍVEL! COMERCIO IN GAME LIBERADO. BONIFICAÇÃO DE 20% PARA QUALQUER VALOR DE DONATE ATÉ 25/06! OFERECEMOS PREMIAÇÕES PARA OS PRIMEIROS 20 CADASTRADOS: 🎁 Premiação Especial: 🎁 100K DE DONATE ✨ (1) Fada Vermelha (3 dias) 📦 (5) Baús de Experiência 🍗 (2) Frangos 🐎 (1) Shire – 30 Dias Mas só para 20 primeiras contas cadastradas. DAREMOS APOIO A GUILDAS QUE VIEREM, PROCURE A ADMINISTRAÇÃO NO GRUPO DO WHATSAPP. Atenciosamente; Equip Infinity
    1 ponto
  20. Tópico Atualizado - 07/08/2024 O Chase Fantasy é um servidor já a 3 anos na ativa e esperamos nos manter na ativa por muito tempo, com missões originais desenvolvidas por nós, visuais exclusivos, mascotes exclusivos, eventos exclusivos, sistemas exclusivos e muitos eventos para você obter desde visuais até mascotes incríveis. Diferente da maioria dos servidores que abrem logo para fechar as portas, prometendo o impossível para atrair a sua atenção, fazer você gastar dinheiro e fechar as portas logo em seguida, nós sempre fomos diferentes e sempre seremos diferentes, temos o foco em trazer a diversão e a sensação que a sua progressão de fato faz efeito, sem fazer você perder seu tempo com grinds exagerados, jogando seu tempo fora pra pouca coisa. Site do servidor para cadastro/download: [Hidden Content] Discord Oficial do Chase Fantasy: [Hidden Content] Recomendamos que entre no Discord pois lá é dado tokens semanais, recompensas por quantidade de membros e compensações de atualização Informações Básicas do Servidor: Nível Máximo: 200 VP Inicial: 15.000 de VP Crie sua conta e receba um kit de iniciante: Confira abaixo imagens com explicações sobre nosso servidor: Sistema de Coleção de Artefatos exclusivo. Sistema de Passe de Batalha sempre com recompensas incríveis e uma loja exclusiva para as moedas do passe de batalha. Pokemons, Chibis e muitos outros pets exclusivos e únicos. Reformulação de Interfaces, mais organizadas e funcionais. Sistema de Runas e Equipamentos do Mestre do Vento (Mais forte atualmente para o nível 200). Continente Vanimir com muitas missões exclusivas sendo desenvolvidas. Refúgio Devastado dos Espíritos - Missão Exclusiva Sacrário dos Espíritos - Missão Exclusiva Vazio (Invasão) Personagem recém lançada: Kallia Personagem já lançada: Decane Personagem já lançada: Ai Forja exclusiva bem organizada com tudo o que você precisa. Muitos sistemas de recompensas para você personalizar seus personagens. Loja VIP com muitos visuais exclusivos e adaptados do Grand Chase Mobile. (Diamantes podem ser obtidos em eventos no DIscord, em missões e outros eventos especiais) Loja de CASH com muitos visuais exclusivos. (VP podem ser obtidos em eventos no DIscord, em quase todas as missões e outros eventos especiais) O que está esperando? Crie sua conta agora mesmo e venha fazer parte da Fantasia.
    1 ponto
  21. ⚔️Guia de Evolução - 🔥👑[Chase Heroes]👑🔥 -⚔️ Nenhuma grande conquista começa grande By: NewAge3 inicie hoje a sua jornada por Ernas e aproveite todos os seus recursos que o servidor tem a oferecer. Rework da Lire Rework do Lass Rework da Arme Crie sua conta e resgate os Tokens no menu do jogo ❤️ Tokens: INICIANTEHEROES Token: HARKYON-KIT-FREE Token: SUPORTE-INICIANTE Token: KitPergaMistico Token: BAUDECARTAENDGAME1 Ao criar a conta no Chase Heroes Voce tambem ira ganhar um bau inicial e outras recompensas no correio Dentro do bau inicial voce tbm ira receber esse items (Pet VIP + visuais VIP GRATIS) Primeira Etapa- Visual Decida com sabedoria o seu primeiro visual, ele ira acompanha-lo até o final de sua jornada. Segunda Etapa- Acessório inicial Equipe-os com a carta Scorpra e Berry Terceira Etapa- Mascote Melhor Mascote para farm e clear inicial. Gratis a Tiny ou vc pode usar o Mascote Nobilitas Vip que é mais forte que vem no bau inicial gratis Quarta Etapa- Missão e Exp NV 1 ao 40 calabouçcos NV 40 ao 85 Portal, se quiser rushar lvl. NV 85-100 Forje seu primeiro titulo de 300% exp I played Season 1, Antigo Castelo S1 NV 90-100 Compre a Missão de Nivel 90- Passo 1 na loja heroica. NV 70 Equipe-se com os equipamento da fenix fantasma Na loja de cash procure por aprovação do ferreiro e compre-a Suba de nivel na Torre das ilusões 80-90 e equipe-se com os itens magi ancestral já no nivel 80 Quinta Etapa- Eventos e equipamentos Entre na sua residencia diariamente para regar sua arvore e receber o buff da Fruta dourada Cada personagem que vc upa e pega classe, voce é recompensado com buff para todos os personagens, ao pegar todas as classes voce ganhara esse BUFF na Conta toda: Clique aqui ou na imagem pra ver o tutorial Como Ganhar Cash Grátis? R: Pelo minigame no Launcher ou Pelos Minigames Diarios do Discord Minigame - Pelo Launcher - Grand Chase Survival: Sobreviva o primeiro round, vc fica imortal enquanto esta na dash, so perde a imortalidade se atacar. As Skills Vao te auxiliar na sobrevivencia. Segurar XXX solta Magia e te ajuda a manter distancia, ZZZZ carrega mana e tem otimo dano. Apos concluir o primeiro STAGE, voce irá ter 3 pontos de talentos e mais ou menos 300R$ de moedas do jogo. na skill corte selestial pegue no min ate a 3ª habilidade, essa skill te dara 10% de hp toda vez que usar a skill se acertar pelo menos 1 inimigo. isso te mantera vivo, skill de rapida recarga otimo beneficio. A Loja e meio aleatorio os itens, sempre vai faltar 1, porem tem um bugzin maroto que e so sair da loja e voltar que atualiza a lista de novo, podendo comprar novamente. Comprem o Poder Divino, ira liberar uma nova habilidade, e toda vez que vc acertar um Critico vai cair um raio do ceu e acertar um inimigo aleatorio, evolua a habilidade para acertar mais inimigos e ter mais dano. ira liberar a skill na arvore de talento, apos a primeiro stage ja e possivel comprar a cada Stage ganhara 2 pontos de talentos, podendo distribuir conforme sua vontade, recomendo pegar o poder divino completo primeiro, pra liberar a skill lendaria que ajudara bastante Como a regra do poder divino é "ele cai toda vez que bate critico" é só comprar acerto critico na area de treinamento de atributos. aumentando sua chance de critico o raio acerta mais vezes, as skilss dao mais dano. distribua o dinheiro ganhado no jogo como prefirir Como temos skill que recupera HP n precisamos de poções de HP, compramos apenas quando esta sobrando dinheiro. use dash para nao levar dano dos bosses enquanto carrega mp pra matar com skill (mais seguro) Para Acessar o discord Clica Aqui ou na imagem a baixo: Post destinado ao Guia de evolução do servidor privado de Chase Heroes se quiser baixar acesse o post correto:
    1 ponto
  22. Olá, tudo bem com vocês? bom vim compartilhar com vocês uma source code External para quem quiser estudar. Para que o Cheat Funcione é necessário carregar o Driver dele, arraste o KernelCheat.sys para kdmapper_Release.exe e só depois de abrir o CrossFire, você abre o Cheat Download: [hide][Hidden Content]] Scann: [Hidden Content]==
    1 ponto
  23. Server Mid-Hard Play-Win Server Classic Gameplay Hunt Based PT-BR and ENG CLIENT Opening 5/1/26 LINK REMOVIDO.
    1 ponto
  24. Usei bastante esse bot lá em 2023, e como me solicitaram resolvi postar pra vocês usarem. Não vou me dar o trabalho de subir em algum repo, mas tá ai. Esse bot simula o cliente do wyd via web (sem ambiente 3d), pela web dá pra fazer várias coisas: - Logar em uma conta - Ligar macros - Deletar itens - Equipar Itens - Filtrar drop por ai vai. Sei que usa sveltekit(sem runas), .NET, ravendb e Docker in Docker para img do ovpn para usar VPN e burlar limite de IP (acho que é opcional sei lá). Não lembro pra qual servidor estava setado, se virem ai. Suponho que só de subir docker-compose funcione, desde que corrija a keytable e altere algum pacote ou outro pra versão correta do teu servidor. Essa base rodou muito tempo também pra inflar numero de jogador ativo em servidor, já que a movimentação dos bots acaba passando batido pelos players, e acabam achando que são players de verdade [Hidden Content]
    1 ponto
  25. Olá! Quem conhece sabe: o produto fala por si, sempre inovando, trazendo funcionalidades novas e sendo constantemente atualizado. *Macro Lan *Filtro de drop com add *Auto agrupar *Auto utilizar *Procurar add com replation *Auto click em npc **Visual Script por nodes ( crie qual quer tipo de macro através de nodes, o céu é o limite ) * Diversas outras funcionabilidades *** Macro Agua para Cons ( auto grupo, notificação por sms ) *** Macro Pesa para Cons (auto grupo, notificação por sms) * Suporte a scripts em lua ( obsoleto, visual script é seu sucessor ) ** Em beta *** serviço extra, preço a parte Em breve vou documentar os nodes e criar os tutorais. Screenshots: Visual Script:
    1 ponto
  26. 🎮 WYD Olympians of Asgard — EXPERIÊNCIA ÚNICA E RECOMPENSADORA! 🎮 🌟 Versão do Servidor: 7.79 🌟 ✨ Detalhes do Servidor: Drop: Medio/Medio ⚡ Up: Medio/Medio 🚀 Composição: 30% ⚔️ 🔥 Evoluções liberadas no servidor 🔥 👤 Mortal — até level 400 🛡 Arch — até level 400 ✨ Celestial / Sub-Celestial — até level 200 💡 Sistemas Exclusivos 💡 🌍 Servidor pensado para jogar FREE 🗃️ Droplist com filtro de drop 🗃️ Sistema Lan Mortal 351+ Sistema Anti Macro 🗃️ Sistema Lan Arch 300+ 🗃️ Sistema de Fragmentos das Almas 🔍 Limite de conta (3) ⚔️ Circulo de Valhalla (TODOS CONTRA TODOS) ⚔️ Batalha do Olimpo (GRUPO VS GRUPO) 🌍 Sistema Guerra entre Reinos 🔍 Player Info 🏆 Ranking Atualizado / PVP / LEVEL 🔍 e Outras Novidades SISTEMA EXCLUSIVO ⚔️ Circulo de Valhalla (TODOS CONTRA TODOS) 🏆 Ranking Top 10 Valhalla por Wins 🏆 Caso de empate por Wins , O Desempate e Por Kills ( Com reset todo Sexta Feira as 23:00 entregrando itens para os top 10) 🏆 Top 1 Valhalla Da Semana Ganha a Coroa de Valhalla 🏆 Obejetivo e defender para nao perde para outro a Coroa de Valhalla 🏆 Até a proxima Atualização do Ranking 🌊 Macro de Pergaminho Água 🌊 Macro de Pesadelo ⚖️ Sistema de Balanceamento: PVP e PVE 🔒 Sistema Vip / Painel Vip (Desativado) 🎒 Painel Boss Exclusivo 🗄️ RMT Mercado Global 🖥️ Resoluções Widescreen sem distorções 🛒 Loja Fantasma 📦 Loja de Donate 🔧 Novidades de Npcs Composição e Recursos: ⚙️ Recicladores 💎 Novos slots para colar e cinto 🌍 ⚙️ Outras Novidades 🔗 Horarios do Servidor 🔗 GUERRA DE CIDADES: Horario: 20:00 (Domingo) GUERRA DE NOATUN: Horario: 21:00 (Domingo) GUERRA DE TORRES: Horario: 21:00 (Segunda a Sexta) KEFRA: Horario: 18:00 (Sexta Feira) (Drop Global) GUERRA ENTRE REINOS (RVR): Horario: 19:00 (Segunda a Sexta) 🔥 POR QUE ESCOLHER O Olympians Servers 🔥 ✅ Atendimento ✅ Ticket Site ✅ Equipe de Financeira ✅ Equipe de Gms ✅ Time dedicado, sempre ouvindo os players! 💬 QUER FICAR POR DENTRO DAS NOVIDADES? Fique ligado, em breve revelaremos nossos parceiros e divulgadores oficiais! 💪 🔗 LINKS ÚTEIS 🔗 🌐 Site:[Hidden Content] 📱 Grupo do WhatsApp:[Hidden Content] 🌟 Prepare-se A verdadeira Essência do MMORPG Está de Volta com o Olympians of Asgard! 🌟 TRAILER OFICIAL
    1 ponto
  27. [Hidden Content]
    1 ponto
  28. Fala pessoal blz. Bom comentei em outro tópico que estava fazendo um conversor de arquivos do WYD. Estou fazendo para o meu projeto, porem esta ficando bem interessante e vou compartilhar com vocês para terem uma ideia do que a ferramenta será capaz. Usa DirectX 11. Conseguimos trabalhar com todos os arquivos do cliente. .MSH .MSA .WYS .WYT .BON .ANI .TRN e etc. Temos o modo de pré-visualização conseguimos ver além da meshs as animações e etc., Se temos um .MSH que possui um .BON e um .ANI associados quando carregamos o .MSH ele puxa automaticamente todos os outros arquivos correspondentes. Logo podemos dar play e ver a animação na preview. Podemos avançar ou retroceder frame a frame e etc. Todos os arquivos carregados ficam na aba da esquerda vc pode ver um a um clicando neles. O mesmo acontece quando carregamos uma .TRN todos os arquivos relacionados são carregados junto, logo conseguimos ver um a um selecionando na esquerda. A aba a direita do preview é a aba de propriedades e fornece informações importantes sobre os arquivos carregados. Conseguimos trabalhar com as meshs de qualquer cliente, na versão que vou postar para vocês não trabalha com as meshs do MYTH. Ainda temos alguma limitações com meshs novas do Global, pois não mapeei todas ainda, então algumas inda ficam transparentes, ou na visualização do .TRN ficam pretas. Na aba Conversores de dados conseguimos trabalhar com alguns arquivos legais como EnvTextureList ainda não trabalhamos com a Env do Global, mas esta em desenvolvimento. Temos Conversores de ItemList e SkillData aqui conseguimos trabalhar com arquivos da TMProject e do Global tanto leitura quando conversão BIN <--> CSV. Temos um Editor de ServerList.bin e trabalhamos com arquivos da TMProject e do Global basta carregar editar e salvar. Temos um Conversor de AttributeMap DAT <--> CSV logo converte para .CSV edita e converte novamente para .DAT A versão completa que tem os conversores de meshs todos habilitados, nessa versão da pra ver exatamente quais os arquivos suportados. Ainda temos um erros de encode nas mensagens do app e estou corrigindo aos poucos, pois são só estéticos. seguem algumas prints segue o scan - teve um apontamento, porem falso positivo, o app não tem assinatura digital então acusa... podem usar tranquilamente que não tem nada malicioso. VirusTotal Download GuiCan Acho que é isso, caso encontrem algum bug que não citei favor reportarem. A sim estava me esquecendo, no roda pé do app mostra as teclas de atalho.
    1 ponto
  29. 🔥SERVIDOR ONLINE 🔥 🌐Redes Sociais 🌍 Site: [Hidden Content] 💬 Discord: [Hidden Content] 📸 Instagram: [Hidden Content] 📱 WhatsApp: [Hidden Content]
    1 ponto
  30. É um cheat básico de vento 0 e sempre pangya Execute como admin e para encerrar é só fechar o jogo. [Hidden Content] Download [Hidden Content] Scan [Hidden Content] Bom aproveito!
    1 ponto
  31. Alguém tem alguma conta válida do prime ?? Se puder passar por privado melhor, o carto é ir filtrando quem pode acessar até achar o infeliz que fica trocando e prejudicando todo mundo
    1 ponto
  32. O arrependimento de um post ai, tem gente que é decepção. “Conhecimento bom é conhecimento compartilhado” vendendo base, ferramenta e pagando d humilde usando base bugada no canal. Tinha um cara aí que soltava conteúdo mas na intenção de se promover pra vender e passar a perna em quem caía
    1 ponto
  33. As regras são simples: ✅ Siga nossa página no Facebook e no Instagram ❤️ Curta o post 👥 Marque 1 amigo nos comentários Só isso! Não é mais necessário compartilhar. 🎉 Lembre-se: pode participar pelo Facebook, pelo Instagram ou pelos dois — quanto mais tarefas fizer, mais pontos acumula e mais chances tem de ganhar! Nossa vontade é que todo mundo participe e tenha uma chance real de ganhar. Esse sorteio é pra vocês que estão aqui desde o início acreditando nesse projeto! 🙏 🎁 São 20 ganhadores de R$ 200,00 em Infinity Points cada! 🔗 Acesse o link e participe agora: [Hidden Content] 📅 Sorteio encerra: 30/04/2026 ⚠️ Observação: No dia do sorteio será verificado manualmente se cada participante realmente curtiu o post, seguiu a página e marcou 1 amigo nos comentários. Quem não tiver feito nenhuma das duas será desclassificado. O sorteio será realizado ao vivo e gravado. ⚔️ "O farm te prepara. O PVP te define." ∞ G2K 🌐Redes Sociais 🌍 Site: [Hidden Content] 💬 Discord: [Hidden Content] 📸 Instagram: [Hidden Content] 📱 WhatsApp: [Hidden Content]
    1 ponto
  34. Beleza mas esse tutorial não serve de nada sem essa ferramenta que vc usou em específico. Em qualquer outra esse tutorial tomaria rumos muito diferentes.
    1 ponto
  35. ATENÇÃO! O CHEAT FICARÁ FREE ATÉ 01/05/2026,APROVEITE! Fala seus arr0mbados, trago para a comunidade um WALLHACK INDETECTÁVEL, já faz ANOS que utilizo e nunca desatualizou, joguem com responsabilidade! Sem enrolação, vamos direto ao ponto! 1 - EXECUTE O SEU POINT BLANK E LOGUE NA SUA CONTA; 2 - ATIVE O MODO JANELA (PARA O MELHOR FUNCIONAMENTO DO CHEAT, EVITANDO TRAVAMENTOS); 3 - EXECUTE O ARQUIVO "WALL PREMIUM - LOADER PB" COMO ADMINISTRADOR E FECHE A JANELA DO NAVEGADOR QUE ABRIRÁ; 4 - VOLTE PARA O POINT BLANK, O WALLHACK JÁ ESTARÁ ATIVO (OBS: NÃO EXISTE A OPÇÃO PARA ATIVAR/DESATIVAR). WALLHACK PREMIUM VITALÍCIO APENAS R$25,00 >> CLIQUE AQUI PARA COMPRAR! <<
    1 ponto
  36. 📅 Beta Liberado: 24/04/2026 às 18h 🌐Redes Sociais 🌍 Site: [Hidden Content] 💬 Discord: [Hidden Content] 📸 Instagram: [Hidden Content] 📱 WhatsApp: [Hidden Content]
    1 ponto
  37. Alguém consegue o login desse site [Hidden Content]
    1 ponto
  38. Que trabalho absurdo, muito foda isso que tu ta fazendo, é como se tivesse um servidor na versao do global, que dahora. Eu estou focado em um outro projeto, se nao tentaria te ajudar em algo. Mas espero que tu consiga evoluir muita coisa e obrigado por compartilhar com a comunidade!
    1 ponto
  39. MEUS CANAIS DE VÍDEOS HC CURSOS E TUTORIAIS 🎬 ▶️ PLAYLIST DO MEU CANAL NO YOUTUBE 🎬 ▶️ VEICARECA GAMES 🎬 ▶️ PLAYLIST DO MEU CANAL NO YOUTUBE 🎬 ▶️ 🎮 Fala, galera! Sejam bem-vindos ao canal! Se você joga WYD (With Your Destiny) e está cansado daquele editor de painéis antigo, ultrapassado e cheio de limitações… ESSE VÍDEO É PARA VOCÊ! 🔥 📌 Eu estava desenvolvendo um projeto que seria VENDIDO, mas resolvi COMPARTILHAR DE GRAÇA com a comunidade. Porque todo mundo merece uma ferramenta digna, né? 🖌️ **O que esse editor tem de especial?** ✅ Interface gráfica MODERNA e atualizada ✅ Trabalha DIRETAMENTE nos painéis com a imagem (nada de ficar decorando códigos!) ✅ Muito mais rápido e intuitivo ✅ Compatível com os painéis do WYD ✅ Ideal para criar, editar e organizar seus painéis de forma profissional 💡 Chega de sofrer com ferramentas jurássicas! Aqui você vai ver na prática como esse editor transforma o trabalho com painéis. 👇 **DOWNLOAD:** 🔗 📁 CLIQUE AQUI PARA BAIXAR O EDITOR NA DESCRIÇÃO DO VÍDEO ⚠️ **Importante:** A ferramenta é totalmente gratuita, mas se quiser apoiar o canal, deixe aquele like e se inscreva! Isso ajuda demais a trazer mais conteúdos exclusivos. 💬 Dúvidas ou sugestões? Manda aí nos comentários! 🔔 Se inscreva no canal e ative o sininho para não perder nenhum conteúdo sobre WYD e ferramentas exclusivas! #WYD #WYDGlobal #EditorDePainéis #MMORPGRetrô #WYDBrasil #FerramentasWYD
    1 ponto
  40. Mano não ta dando para acessar as conta do prime vídeo direto pede um código para validar a senha Tem um indiota que ta trocando as senhas direto palhaço criança sem conduta não tem limite mulecagem, o prime tá pedindo código
    1 ponto
  41. Crunchyroll NÃO TÁ FUNCIONANDO NÃO! Crunchyroll NÃO TÁ FUNCIONANDO NÃO! MUDARAM A SENHA DA CRUNCHYROLL
    1 ponto
  42. Conheci essa IA sem censura: pergunta o que quiser que ela responde. Tem limite diário, mas gera muitos tokens e mantém as conversas. [Hidden Content]
    1 ponto
  43. Seja bem-vindo ao Point Blank ICE, o servidor feito para quem busca ação intensa, estabilidade e diversão sem limites. Aqui você encontra um gameplay equilibrado, eventos constantes e uma comunidade ativa pronta para o combate. 💎 Destaques do servidor: Servidor estável e otimizado Vip Barato!! 250k de cash e gold no cadastro! Eventos exclusivos e recompensas especiais Sistema VIP diferenciado Suporte ativo e administração dedicada Atualizações frequentes ❄️ Point Blank ICE é mais que um servidor, é o campo de batalha onde só os melhores sobrevivem. Prepare seu arsenal, monte seu time e venha dominar o gelo da guerra! Links abaixo!! Discord para se cadastrar e para comunidade > [Hidden Content] Site Para Ranking > [Hidden Content] Download > [Hidden Content]
    1 ponto
  44. Fala, pessoal! Resolvi trazer um resumo pequeno mas um pouco detalhado sobre o repositório OSINT Brazuca, do GitHub — um dos melhores hubs de recursos OSINT focados no Brasil. Ideal para quem trabalha com investigação, segurança, jornalismo, auditoria ou projetos educacionais. O que é o OSINT Brazuca? O OSINT Brazuca é um repositório público criado para centralizar fontes, links, bases de dados e ferramentas OSINT com foco específico no contexto brasileiro. Ele segue a licença MIT, permitindo uso livre e modificação. Estrutura do Repositório: O repositório é composto principalmente por: README.md bem completo, com índice de dezenas de categorias OSINT. assets/: imagens e recursos visuais usados no projeto. LICENSE: licença MIT. Wiki: seção extra com informações adicionais (em desenvolvimento). Principais Categorias e Conteúdos O README é dividido em várias áreas temáticas úteis para investigações • Benefícios Sociais Links para programas como Bolsa Família, Auxílio, cadastros sociais etc. • Pessoas Desaparecidas Sites e bancos de dados nacionais e estaduais. • Consulta de Processos Tribunais, e-SAJ, TRFs, BNMP (mandados), justiça estadual e federal. • Consultas de CPF/CNPJ Ferramentas para verificar situação, dados básicos, certidões e informações públicas. • Telecom Consulta de torres (ERBs), infraestrutura de telecom e dados geográficos. • Informação Acadêmica Bases de instituições, currículos, publicações e dados educacionais. • Mapas e Georreferenciamento Portais de mapas, APIs e dados geoespaciais do Brasil. • Saúde Bases abertas e dados públicos do setor de saúde. • Redes Sociais Métodos e links para buscas avançadas no Instagram, LinkedIn, X/Twitter etc. • Datasets Públicos Coleções de dados do governo e órgãos públicos. • Transporte (Aéreo, Terrestre e Aquaviário) Sites de rastreio, consultas, malhas de transporte e tracking de ônibus. • Câmeras Públicas (CFTVs) Links para câmeras acessíveis publicamente em diversas regiões. • Domínios .BR Classificação e pesquisa de extensões do registro.br. • Fontes por Estado Brasileiro Listas regionais para consultas específicas por estado. Possíveis Usos na Prática O repositório é valioso para: Investigações OSINT focadas no Brasil Jornalismo investigativo Pesquisas acadêmicas Segurança e auditoria Ativismo e transparência pública Serve como biblioteca de links confiáveis para quem trabalha com coleta e análise de informações abertas. Pontos Fortes: Focado no Brasil Altamente organizado Links úteis e variados Licença permissiva Excelente para consultas rápidas Limitações: Não é uma ferramenta automatizada Depende de serviços externos que podem mudar Alguns links podem ficar desatualizados Pouco conteúdo de scripts ou automação Conclusão: O OSINT Brazuca é uma das melhores coleções de links OSINT brasileiros disponíveis gratuitamente. Ele não faz automação, mas é um catálogo extremamente valioso para investigações e pesquisas envolvendo dados abertos no Brasil. No final deste tópico estarei disponibilizando o link para acesso as ferramentas, espero que aproveitem! Ah como expliquei no começo e um pequeno resumo por que sinceramente e muita coisa kkk a WIKI vai explicar melhor do que eu até a próxima 🫡 OBS: Fiz está postagem pelo celular tentei deixa o mais "organizado" que consegui mesmo mexendo pelo celular. Saudades do meu computador 😔 Se tiver muito engajamento neste tópico eu continuo postando conteúdos desse tipo aqui! LINK DE ACESSO
    1 ponto
  45. DUMP DA CSHELL_X64.DLL E DO CROSSFIRE.EXE PRA QM ESTA COMEÇANDO JÁ É ALGO.. [Hidden Content]
    1 ponto
  46. ATUALIZADO 29/09/2025: [Hidden Content] PATROCINADORA streamingsbarato.com Diversos Serviços streamings com 70% OFF
    1 ponto
  47. Creditos do desenvolvimento e vídeo do nosso amigo Mizael [Hidden Content]
    1 ponto
Esta tabela de classificação está definida para São Paulo/GMT-03:00
×
×
  • Criar Novo...

Informação Importante

Nós fazemos uso de cookies no seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies , caso contrário, vamos supor que você está bem para continuar.