Ir para conteúdo

Os Melhores

Conteúdo popular

Mostrando conteúdo com a maior reputação em 23/05/2026 in todas as áreas

  1. 📌 [LANÇAMENTO] FoxMap Studio V1 — Open Source O editor de mapas mais completo para WYD Fala galera da WebCheats! Se você administra ou está desenvolvendo um servidor de With Your Destiny, sabe o quão trabalhoso e limitado costuma ser o processo de criação e edição de mapas usando ferramentas antigas. Pensando nisso, foi desenvolvido o FoxMap Studio V1, uma ferramenta revolucionária que vai mudar completamente a forma como você customiza o seu servidor! Assista ao vídeo demonstrativo completo e veja a ferramenta em ação: 👉 [Hidden Content] 🔥 O que faz o FoxMap Studio ser diferente? O FoxMap Studio foi criado do zero para ser intuitivo, rápido e extremamente poderoso. Chega de sofrer com ferramentas travadas que exigem reinicializações constantes ou processos manuais complexos. [Hidden Content] [Hidden Content] [/hide] 🌟 Principais Recursos: Edição Visual Completa: Interface limpa, moderna e totalmente interativa para você focar no que realmente importa: a criatividade do seu mapa. Modificações em Tempo Real: Veja cada alteração de terreno, texturas e objetos acontecer instantaneamente na sua tela. Editor Avançado de Terrenos e Alturas: Suba montanhas, crie vales e ajuste o relevo do mapa com pincéis dinâmicos e precisos. Pintura Dinâmica de Texturas: Aplique e misture diferentes texturas de solo diretamente no mapa de forma suave e rápida. Importação e Posicionamento de Objetos 3D: Adicione construções, decorações, portais e elementos de cenário de maneira extremamente simples (com suporte a arquivos .glb/.gltf e conversão inteligente para o formato do cliente). Gestão de Atributos do Mapa: Configure zonas de PvP, áreas seguras (No-PvP), zonas de drop ou teleportes diretamente pela interface do estúdio. Integração Direta com o Cliente: Teste e salve suas alterações diretamente nos arquivos do jogo de forma prática. 📺 Veja o Passo a Passo no Vídeo! No vídeo oficial, mostramos desde a interface de login da plataforma WYD Fox Studio até a criação prática de um cenário completo: Como abrir e carregar os mapas existentes do seu cliente. Utilização das ferramentas de pintura de terreno e elevação de mesh. Importação e rotação livre de objetos e decorações 3D no cenário. Aplicação de efeitos climáticos e iluminação personalizada no mapa. Conversão e salvamento automático dos arquivos para rodar perfeitamente no jogo. Assista aqui: Como Criar Mapas Customizados para WYD — FoxMap Studio 🚀 Como ter acesso? [Hidden Content] A ferramenta conta com uma versão de testes gratuita para você conhecer o potencial do editor. Desenvolvedor: Foxdemo / WYD Fox Studio Para suporte, atualizações constantes e mais ferramentas da nossa suíte de desenvolvimento (Editores de Itens, NPCs, Monstros e Quests em breve!), entre no nosso Discord oficial (link disponível na descrição do vídeo do YouTube). Deixe seu comentário abaixo dizendo o que achou da ferramenta ou qual recurso você gostaria de ver nas próximas atualizações!
    4 pontos
  2. Conteúdo da MARTINA OLIVEIRA, conhecida também como BEIÇOLA DO PRIVACY, PRIVACY DELA GRATIS + Videos vazados totalmente pelada, mostrando e fazendo de tudo. Sem frescura e nem anuncios, basta clicar no link e dar play no video, para ver o Privacy gratis é só se cadastrar. PRIVACY OFICIAL GRÁTIS, BASTA SE CADASTRAR [Hidden Content] QUASE 40 VIDEOS VAZADOS [Hidden Content]
    3 pontos
  3. ⚔️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é 120/UP 120 - 120+ 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
    2 pontos
  4. [Hidden Content]
    2 pontos
  5. 2 pontos
  6. [Hidden Content]
    2 pontos
  7. 🚀 Confira as funções incríveis completamente gratuitas disponíveis no nosso hack! Com foco em performance, praticidade e diversão, você vai turbinar sua experiência como nunca antes! 🔥 🔹 Zerar Tempo de Recarga – Use suas skills o quanto quiser, sem esperar! 🔹 HP Cheio – Mantenha sua vida sempre no máximo. 🔹 MP Cheio – Nunca mais fique sem mana! 🔹 Bloquear Popup – Diga adeus àquelas telas chatas que aparecem no jogo. 🔹 Imã de Itens – Os itens virão direto até você! 🔹 Anti-AFK – Permaneça na sala mesmo se precisar se ausentar por um tempo. 🔹 Pula Diálogos – Corte direto para a ação, sem enrolação . 🔹 Rank SS – Substitui a pontuação da tela para garantir classificação SS. 🔹 Modo Streamer – Oculta textos e detalhes visuais do jogo. 🔹Imã de Monstros – Atrai todos os monstros até o jogador. 🆓 Atenção! Algumas das funcionalidades listadas estão disponíveis gratuitamente por tempo limitado. No futuro, as funções free poderão ser reduzidas, conforme o desenvolvimento do projeto. 📸 Screenshots: 🔧 Como usar: É simples e rápido começar a usar: 1- Baixe o cliente. 2- Abra o programa e clique em “Injetar”. 3- Inicie o Grand Chase normalmente. 4- Pressione [Insert] para exibir ou ocultar o menu. 5- Aproveite todos os recursos e domine o jogo! ⚠️ Aviso: Ao executar o cliente, sempre clique com o botão direito e selecione “Executar como administrador” para evitar problemas de permissão. Certifique-se também de que o Grand Chase não esteja em modo tela cheia, pois isso pode causar falhas durante a injeção. Se você utiliza Steam: Feche completamente a execução da steam e após isso execute a mesma como administrador, também de preferência a execução do Grandchase via atalho ao invés da execução direta na biblioteca da Steam. [Hidden Content] Erro ao injetar no GrandChase? Em alguns casos, é necessário desabilitar o Windows Defender, a proteção em tempo real e o antivírus instalado no sistema. Mesmo que nosso software não seja malicioso, os antivírus podem identificá-lo como uma ameaça falsamente (falso positivo), pois ele realiza operações avançadas de injeção na memória de outro processo — algo comum em cheats ou ferramentas legítimas de modificação de jogos. Isso faz com que algumas proteções bloqueiem o funcionamento correto do injetor ou até excluam arquivos essenciais automaticamente. Garantimos que o produto é seguro e limpo. Desativar temporariamente a proteção permite que a injeção ocorra corretamente. 🗓️ Hack Atualizado em: 17/06/2026
    2 pontos
  8. A Fada estava com erro (bugada), esta é a correção completa para isso. Achei que isso seria uma adição incrível para a comunidade. [Hidden Content]
    2 pontos
  9. Conteúdo da MC MIRELLA, fotos e videos totalmente pelada. Sem frescura e nem anuncios, basta clicar no link e dar play no video. FOTOS E VIDEOS [Hidden Content] COMPILADO COM MUITOS VIDEOS [Hidden Content]
    2 pontos
  10. Um salve pra geral ! Bom, eu comprei essa base (das maos do ~rooh) tem um tempo e estou subindo ela no github para compartilhar com a comunidade, subirei tambem com algumas mudanças que fiz. A base é relativamente boa, e como estou aprendeendo a bricar na parte de programação tem me gerado bons desafios e aprendizados. Infelizmente, estou upando do jeito que peguei direto com quem me vendeu, sem algumas alterações de codigos que ja fiz, mas assim que conseguir editarei aqui colocando isso no github e com algumas alterações. # Fixs que fiz ! - - A interação em grande parte do cliente com a db usa atoi e as vezes retornava null. ! - - Ajustar a validação de janelas que tambem retornava null. ! - - Ajustar e validar as rows de algumas consultas na db( Não me lembro ao certo onde era o problema) tambem retorna null. Tem algumas coisas a mais que fiz, mas essas foram essenciais para que o server não "crashe" e derrube o cliente e/ou a TM. Espero que seja de grande valia para a comunidade e aprendizado de outros. LINK: [Hidden Content] SCAN RAR : [Hidden Content] SCAN .SLN CLIENT: [Hidden Content] SCAN .sln Server: [Hidden Content] Creditos: BnkBrum, SeiTbNao, Guga, BabyLoves, Arkanun1000 [W2PP] VKlafke, hiccupsman, andresantacruz, ErickAlcan, kevinkouketsu
    2 pontos
  11. [Hidden Content]
    2 pontos
  12. 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---
    2 pontos
  13. 📢 Disponibilizando Projeto WYD 2.0 e WYD 7.87 Fala, galera! Estou liberando aqui o projeto do WYD 2.0 e WYD 7.87 para a comunidade. Quero deixar claro que não possuo os créditos originais — recebi esses materiais de um amigo que já não atua mais na área. Se alguém souber ou for o dono dos créditos, basta comentar que eu atualizo o post e adiciono todas as informações corretas, sem problema nenhum. 🙌 Meu objetivo com essa publicação é contribuir com a comunidade, já que notei que muita gente vem vendendo esse conteúdo, mesmo ele estando disponível gratuitamente há bastante tempo. Então estou apenas ajudando a manter o acesso aberto para todos. A intenção aqui é colaboração, transparência e respeito ao trabalho de quem realmente criou. Vamos fortalecer a comunidade juntos! 💙 WYD 2.0 LINK [Hidden Content] SCAN : VirusTotal - File - 9d9f401f81883824e697424e5efffc382fc8edd6d77512119b7c58ed907a6f6e WYD 7.87 LINK [Hidden Content] SCAN : VirusTotal - URL EDIT1: LINK ALTERNATIVO [Hidden Content] OBS: BAIXE POR SUA CONTA E RISCO OS SCAN TAO AI!
    2 pontos
  14. ASSINATURAS ATUALIZADAS Patrocinadora: streamingsbarato.com [Hidden Content] [Hidden Content] [Hidden Content] [Hidden Content] Assinatura será atualizada todos os meses.
    2 pontos
  15. Eternal Kersef - BETA ONLINE! Prepare-se para uma experiência totalmente renovada dentro do WYD! Um servidor pensado nos mínimos detalhes para quem busca inovação, performance e diversão REAL! ⚔️ 𝗦𝗼𝗯𝗿𝗲 𝗱𝗼 𝗦𝗲𝗿𝘃𝗶𝗱𝗼𝗿 🔸 Versão: Clássica 🔸 Experiência: Easy 🔸 Drop: Médio 🔸 Progressão dinâmica 🔸 Quests Mortais: Do Lv. 40 até o 351 🔸 Diversas mecânicas ⚔️ SISTEMAS EXCLUSIVOS ⚔️ ✔️ Arena Real (PvP competitivo de verdade) ✔️ Droplist direto no game (transparência total) ✔️ Sistema de Invasão de Monstros dinâmica ✔️ Sistema de Gráfico Avançado (sombras em mapas, mobs e players) ✔️ Passe de Batalha com recompensas incríveis ✔️ Sistema de Ajudante VIP ✔️ Macro Perga e Macro Pesa otimizados Entre agora mesmo no grupo whatsapp e participe do BETA! [Hidden Content]
    1 ponto
  16. Site: [Hidden Content] (Offline em alguns momentos) GrupoWhatsApp: [Hidden Content] BETA ONLINE INFORMAÇÕES BÁSICAS Site Exlusivo Versão do Servidor: Global 7.99 Experiência: +25% Exp semanalmente. Drop: Médium Evolução: 8 Level Max.: 800 (Acima de Sub +100nv por evolução) Bonus Exp: +50% Finais de semana Limite de Conta: 5 Critico Mágico: Sím Aprendizagem: 600 pontos Imunidade: 200 pontos Slots Extras: 17(Padrão) + 5 Extras(Runas) Sistema Lan: Sim, entrada diária limitada Mercador Negro(RMT): Sim, disponível no site ADICIONAIS Mercado RMT Sistema de Runas Consulta Inf. Autoreconect Macros para up Ant Bot Lan Loja clone Missões diária (Passe de Batalha) Missões de Batalha (Passe de Espolio) Resgate diário Filtro de drop Bosses diários Mascote Replantation Superiores Extrações Superiores Crafts exclusivos CAMPO DE TREINAMENTO /novato: Garanta Runa iniciante + Shire(3D) + Passe de Batalha(3D)Imóvel + Poções: Saúde, Sephira e Divina por 24h. Garanta todos os Buffs de Foema para ajudar na sua jornada clicando no NPC Carbunkle. Chegue até o final do terceiro portão de derrote o Orc Sniper. Adquira o Emblema Orc e troque no unicónio no inicio da quest por recompensas incriveis. Limite de level: 35. 1xAmuleto dos Amantes 1xChocolate do Amor 10xClasse A 1xAnel Branco dos Amantes 1xArma Sephira C RECOMPENSA DIÁRIA Lv40-115 Defensor da Alma: 60.000xp + 5.000 Ouro Lv116-191 Jardim dos deuses: 120.000xp + 7.000 Ouro Lv192-265 Ressurreição Cav. Negro: 250.000xp + 9.000 Ouro Lv266-321 Hidra Imortal: 350.000xp + 12.000 Ouro Lv321-351 Início da Infelicidade: 500.000xp + 15.000 Ouro PASSE DOS ESPOLIOS CONHEÇA O PROJETO COMPLETO EM NOSSO SITE! 90 Dano + 3%Hp + 7% do ataque base do player com ataque em áera, e envenenamento. 15% Magia + 30 Def + 10% do ataque base do player com ataque único, e congelamento. 5 Skill + 5 Imunidade + 1,5% Critico + 15% de chance de ressucitar ao ser eliminado. CRAFTS
    1 ponto
  17. 🎮 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
  18. Download The password for Zip file is:123
    1 ponto
  19. Olá galera, 🎮 Fatal Chase Cheats disponíveis: AutoKill – Mata automaticamente os mobs AutoBoss – Avança direto para o stage do boss ItemVac – Coleta os drops Automaticamente Serviços (sem precisar passar dados da conta): XP Hack → Sobe do nível 0 ao 85 em poucos minutos Complete Quest → Finaliza quests de matar monstros ou pegar chaves em segundos (sem precisar matar 1000+ monstros) [Hidden Content] [Hidden Content] 📌 Discord para suporte e mais informações: 0iiveira
    1 ponto
  20. 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
  21. [Hidden Content]
    1 ponto
  22. 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); }
    1 ponto
  23. CHASE HEROES — NOVA ERA DOS HEROES COMEÇOU ! 14/05/2026 [ ON ] Grand Chase Heroes - Servidor Season 5 PT 3 CADASTRO DE CONTAS NO LAUCHER A O CADASTRAR GANHE BONUS PARA COMEÇAR ALGUNS TOKENS PARA ACELERAR SUA EVOLUÇÃO KitPergaMistico SUPORTE-INICIANTE INICIANTEHEROES HARKYON-KIT-FREE ( APENAS OS 50 PRIMEIROS KIT-BERKAS001 BAUDECARTAENDGAME1 Chase_Heroes#143415 ( SET MAGI ) GLADIADOR2026 ( VISUAL GLADIADOR ) NO SERVIDOR GRAND CHASE HEROES ALGUNS CHAR TOMARAM ALGUNS REWORKS EM SUAS HABILIDADES LIRE MUDANÇAS EM VIDEO ARME MUDANÇAS EM VIDEO LASS MUDANÇAS EM VIDEO ⚡ PERSONAGENS EM DESTAQUE ✔️ Lin — META ✔️ Ryan — Todas classes buffadas ✔️ Elesis — Todas classes buffadas ✔️ Ronan - Buffado ✔️ Uno — Buffado ✔️ Azin — Buffado ✔️ Jin — Buffado ✔️ Zero — Buffado ✔️ Dio — Balanceado ✔️ Veigas — Balanceado ✔️ Holy - Buffado ✔️ Mari - Buffado ✔️ Ai - Balanceado ✔️ Peryton - Buffado TODOS OS CHARS ATE DECANE E AI KALLIA E IRIS EM TRABALHO TAMBEM TEMOS CONTEUDOS PARA DONATE 🔥 ALGUMAS OUTROS INFORMAÇÃO 🔥 ⚔️ Level Máximo 101 🎮 Farme de CASH através de Mini Games no Launcher 🎉 Eventos dos GMs constantemente ativos 💬 Eventos exclusivos no Discord valendo CASH 📖 Guias Evolutivos disponíveis no Discord 🛡️ Staff extremamente ativa e sempre presente no chat ✨ ITENS E CONTEÚDOS EXCLUSIVOS ✨ 🔹 Títulos Exclusivos PLACA JONNY THUG Pierc do Void Pierc do Renak - Necessário Craftar Apenas Uma Vez Pode ser utilizado em TODOS os personagens ⚖️BALANCEAMENTO CONFORME VOCÊS PEDEM ⚖️ No Chase Heroes o feedback dos jogadores realmente importa. Estamos constantemente ajustando personagens, skills e conteúdos para deixar o servidor mais divertido e equilibrado. DISCORD : CLICA AQUI Atraves do Discord você tem acesso ao Cadastro e Download
    1 ponto
  24. Pack Grátis - MC RAPOSINHA | Michelle Rabbit MC RAPOSINHA Download Pack: [Hidden Content] MICHELLE RABBIT Download Pack: [Hidden Content]
    1 ponto
  25. Basta deslizar e assistir o quanto quiser de vídeos +18 curtos e longos! [hide][Hidden Content]] Basta clicar na opção do Tiktok e aproveitar os milhares de vídeos!
    1 ponto
  26. struct STRUCT_MOB { char MobName[NAME_LENGTH]; // Nome do MOB/NPC/Player 1FDECA0 byte 0 a 15 dentro da STRUCT_MOB da TMSrv 1.7 char Clan; // Reino ou Grupo do MOB/NPC/Player 1FDECB0 byte 16 dentro da STRUCT_MOB da TMSrv 1.7 char Merchant; // Identificador da merchant 1FDECB1 byte 17 dentro da STRUCT_MOB da TMSrv 1.7 unsigned short Guild; // Identificador da Guild do MOB/NPC/Player 1FDECB2 byte 18 a 19 dentro da STRUCT_MOB da TMSrv 1.7 char Class; // Identificador da classe do MOB/NPC/Player 1FDECB4 byte 20 dentro da STRUCT_MOB da TMSrv 1.7 unsigned char Rsv; // AffectInfo 1FDECB5 byte 21 dentro da STRUCT_MOB da TMSrv 1.7 short Quest; // QuestInfo 1FDECB6 byte 22 a 23 dentro da STRUCT_MOB da TMSrv 1.7 int Coin; // Gold atual do MOB/NPC/Player 1FDECB8 byte 24 a 27 dentro da STRUCT_MOB da TMSrv 1.7 unsigned int Exp; // Experiencia atual do MOB/NPC/Player 1FDECBC byte 28 a 31 dentro da STRUCT_MOB da TMSrv 1.7 short SPX; // Ultima posição X salva com a Gema Estelar 1FDECC0 byte 32 a 33 dentro da STRUCT_MOB da TMSrv 1.7 short SPY; // Ultima posição Y salva com a Gema Estelar 1FDECC2 byte 34 a 35 dentro da STRUCT_MOB da TMSrv 1.7 STRUCT_SCORE BaseScore; // Status base 1FDECC4 byte 36 a 63 dentro da STRUCT_MOB da TMSrv 1.7 STRUCT_SCORE CurrentScore; // Status atual 1FDECE0 byte 64 a 91 dentro da STRUCT_MOB da TMSrv 1.7 STRUCT_ITEM Equip[MAX_EQUIP]; // Itens equipados no personagem 1FDECFC byte 92 a 219 dentro da STRUCT_MOB da TMSrv 1.7 STRUCT_ITEM Inventory[MAX_INVENTORY]; // Itens do inventario 1FDED7C byte 220 a 731 dentro da STRUCT_MOB da TMSrv 1.7 unsigned int LearnedSkill; // Skills Aprendidas - Dividido em 4 categorias (00 _ 00 _ 00 _ 00) 1FDEF7C byte 732 dentro da STRUCT_MOB da TMSrv 1.7 unsigned short ScoreBonus; // Pontos de Status (Força, Inteligencia, Dextreza, Constituição) 1FDEF80 byte 736 dentro da STRUCT_MOB da TMSrv 1.7 unsignes short SpecialBonus; // Pontos de Apreendizagem (Aprender Arma, Especial1, Especial2, Especial3) 1FDEF82 byte 738 dentro da STRUCT_MOB da TMSrv 1.7 unsignes short SkillBonus; // Pontos de Skill 1FDEF84 byte 740 dentro da STRUCT_MOB da TMSrv 1.7 char Critical; // Chance de Hits Criticos 1FDEF86 byte 742 dentro da STRUCT_MOB da TMSrv 1.7 char SaveMana; // 1FDEF87 byte 743 dentro da STRUCT_MOB da TMSrv 1.7 char SkillBar1[4]; // Salva o id de 4 skills da barra 1 //char SkillBar1[0]; 1FDEF88 byte 744 dentro da STRUCT_MOB da TMSrv 1.7 //char SkillBar1[1]; 1FDEF89 byte 745 dentro da STRUCT_MOB da TMSrv 1.7 //char SkillBar1[2]; 1FDEF8A byte 746 dentro da STRUCT_MOB da TMSrv 1.7 //char SkillBar1[3]; 1FDEF8B byte 747 dentro da STRUCT_MOB da TMSrv 1.7 char GuildLevel; // Identifica se o Player é membrou ou lider do clan 1FDEF8C byte 748 dentro da STRUCT_MOB da TMSrv 1.7 unsigned char Magic; // multiplicador de dano magico 1FDEF8D byte 749 dentro da STRUCT_MOB da TMSrv 1.7 char RegenHP; // Regeneração de HP 1FDEF8E byte 750 dentro da STRUCT_MOB da TMSrv 1.7 char RegenMP; // Regeneração de MP 1FDEF8F byte 751 dentro da STRUCT_MOB da TMSrv 1.7 char Resist[4]; // Identifica as resistencias Sagrado - Trovão - Fogo - Gelo //char Resist[0]; 1FDEF90 byte 752 dentro da STRUCT_MOB da TMSrv 1.7 //char Resist[1]; 1FDEF91 byte 753 dentro da STRUCT_MOB da TMSrv 1.7 //char Resist[2]; 1FDEF92 byte 754 dentro da STRUCT_MOB da TMSrv 1.7 //char Resist[3]; 1FDEF93 byte 755 dentro da STRUCT_MOB da TMSrv 1.7 } class CMob // 1724 size original da CMob 7.56 { public: //O size original da STRUCT_MOB na TMSrv 7.56 é 756 bytes STRUCT_MOB MOB; //0 - 755 //1FDECA0 addr inicial da pMob na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D84AC0 - STRUCT_MOB 100% Mapeada int Hold; //756 - 759 //1FDEF94 - CORRETO - TMSrv 7.57 7D84EC0 - 1024 - 1027 - 0x400 int ChatBlockTime; //760 - 763 //1FDEF98 - CORRETO - TMSrv 7.57 7D84EC4 int NightmareTicket; //764 - 767 //1FDEF9C (escritura do pesadelo para celestial+) - CORRETO - TMSrv 7.57 int Mileage; //768 - 771 //1FDEFA0 addr da Mileage na TMSrv 7.56 - CORRETO - TMSrv 7.57 //guarda a quantia de cash que tem na conta int unk_1FDEFA4; //772 - 775 //1FDEFA4 TMSrv 7.57 int Fame; //776 - 779 //1FDEFA8 addr da Fama na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D8514C int KefraTicket; //780 - 783 //1FDEFAC addr da KefraTicket na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D84ED8 int unk_1FDEFB0; //784 - 787 //1FDEFB0 alguma coisa haver com a fada do vale TMSrv 7.57 7D84EDC STRUCT_AFFECT SaveAffect[MAX_AFFECT]; //788 - 915 //1FDEFB4 - é uma STRUCT_AFFECT e é usada na save and quit talvez para salvar os affects do celestial ou algo assim - addr 004B859D char isChatBlock; //916 //1FDF034 - 0 chat sem bloqueio - 1 chat bloqueado - CORRETO - TMSrv 7.57 7D84FE0 - 1312 - 0x520 char CristalQuest; //917 //1FDF035 - CORRETO - TMSrv 7.57 7D84FE1 - 1313 - 0x521 //verificação do andamento da quest dos cristais chama a função 00414E70(CristalQuest, i) i = 0; i < 4; i++ //00414ED0 provavelmente a função que seta o uso do cristal (1 << i) & CristalQuest //(0: Não iniciou a quest - 1: usou o cristal Elime - 2: usou o cristal Silphed - 4: usou o cristal Thelion - 8: usou o cristal Noas) char isArchBlockedLvl; //918 //1FDF036 - CORRETO - TMSrv 7.57 7D84FE2 - 1314 - 0x522 char ArchLvlandFuryStone; //919 //1FDF037 - CORRETO - TMSrv 7.57 7D84FE3 - 1315 - 0x523 //valor vai de 1 a 8 - lvl do arch quando o celestial foi criado ate o 5 + resets pedra da furia 6 a 8 char unk_1FDF038; //920 //1FDF038 - relacionado a bloqueio de lvl char isBlockedLvl; //921 //1FDF039 - relacionado a bloqueio de lvl - CORRETO - TMSrv 7.57 7D84FE5 - 1317 - 0x525 char unk_1FDF03A; //922 //1FDF03A - relacionado a bloqueio de lvl char unk_1FDF03B; //923 //1FDF03B - relacionado a bloqueio de lvl char unk_1FDF03C; //924 //1FDF03C - relacionado a bloqueio de lvl char isHardCore; //925 //1FDF03D - Relacionado ao Hardcore - CORRETO - TMSrv 7.57 7D84FE9 - 1321 - 0x529 char soulType; //926 //1FDF03E - salva a config da Soul vai de 1 - 10 - CORRETO - TMSrv 7.57 7D84FEA - 1322 - 0x52A char isGodOrSub; //927 //1FDF03F - celestial:0 sub:1 - CORRETO - TMSrv 7.57 7D84FEB - //size da Struct que salva as infos do celestial e do sub é 68 bytes na 756 e 96 bytes na 757+ STRUCT_SUBCLASSINFO saveSubClassInfo[2];//932 - 1067 //1FDF044 - Salva as Infos do Cele e do Sub - CORRETO - TMSrv 7.57 7D84FF0 - int unk_1FDF0E0; //1088 - 1091 //1FDF0E0 - CORRETO - TMSrv 7.57 7D850C4 - STRUCT_AFFECT Affect[MAX_AFFECT]; //1204 - 1331 //1FDF154 addr da Affect na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85148 - 1672 - 1927 - 0x688 //Originalmente na TMSrv 7.56 tem 1332 bytes antes da variavel Mode ou seja do 0 ao 1331 - TMSrv 7.57 tem 2084 bytes antes da variavel Mode ou seja do 0 ao 2083 int Mode; //1332 - 1335 //1FDF1D4 addr da Mode na TMSrv1.7 - CORRETO - TMSrv 7.57 7D852E4 - 2084 - 2087 - 0x824 int Leader; //1336 - 1339 //1FDF1D8 addr da Leader na TMSrv1.7 - CORRETO - TMSrv 7.57 7D852E8 - 2088 - 2091 - 0x828 int Formation; //1340 - 1343 //1FDF1DC addr da Formation na TMSrv1.7 - CORRETO - TMSrv 7.57 7D852EC - 2092 - 2095 - 0x82C int RouteType; //1344 - 1347 //1FDF1E0 addr da RouteType na TMSrv1.7 - CORRETO - TMSrv 7.57 7D852F0 - 2096 - 2099 - 0x830 int LastX; //1348 - 1351 //1FDF1E4 addr da LastX na TMSrv1.7 - CORRETO - TMSrv 7.57 7D852F4 - 2100 - 2103 - 0x834 int LastY; //1352 - 1355 //1FDF1E8 addr da LastY na TMSrv1.7 - CORRETO - TMSrv 7.57 7D852F8 - 2104 - 2107 - 0x838 int LastTime; //1356 - 1359 //1FDF1EC addr da LastTime na TMSrv1.7 - CORRETO - TMSrv 7.57 7D852FC - 2108 - 2111 - 0x83C int LastSpeed; //1360 - 1363 //1FDF1F0 addr da LastSpeed na TMSrv1.7 - CORRETO - TMSrv 7.57 7D85300 - 2112 - 2115 - 0x840 int TargetX; //1364 - 1367 //1FDF1F4 addr da targetX na TMSrv1.7 - CORRETO - TMSrv 7.57 7D85304 - 2116 - 2119 - 0x844 int TargetY; //1368 - 1371 //1FDF1F8 addr da TargetY na TMSrv1.7 - CORRETO - TMSrv 7.57 7D85308 - 2120 - 2123 - 0x848 int NextX; //1372 - 1375 //1FDF1FC addr da NextX na TMSrv1.7 - CORRETO - TMSrv 7.57 7D8530C - 2124 - 2127 - 0x84C int NextY; //1376 - 1379 //1FDF200 addr da NextY na TMSrv1.7 - CORRETO - TMSrv 7.57 7D85310 - 2128 - 2131 - 0x850 int NextAction; //1380 - 1383 //1FDF204 addr da NextAction na TMSrv1.7 - CORRETO - TMSrv 7.57 7D85314 - 2132 - 2135 - 0x854 char Route[MAX_ROUTE]; //1384 - 1407 //1FDF208 addr da Route na TMSrv1.7 - CORRETO - TMSrv 7.57 7D85318 - 2136 - 2159 - 0x858 int WaitSec; //1408 - 1411 //1FDF220 addr da WaitSec na TMSrv1.7 - CORRETO - TMSrv 7.57 7D85330 - 2160 - 2163 - 0x870 int PosX; //1412 - 1415 //1FDF224 addr da PosX na TMSrv1.7 int PosY; //1416 - 1419 //1FDF228 addr da PosY na TMSrv1.7 int Segment; //1420 - 1423 //1FDF22C addr da Segment na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D8526C - 1964 - 1967 - 0x7AC int SegmentX; //1424 - 1427 //1FDF230 addr da SegmentX na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85270 - 1968 - 1971 - 0x7B0 int SegmentY; //1428 - 1431 //1FDF234 addr da SegmentY na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85274 - 1972 - 1975 - 0x7B4 int SegmentListX[MAX_SEGMENT]; //1432 - 1451 //1FDF238 addr da SegmentListX na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85278 - 1976 - 1995 - 0x7B8 int SegmentListY[MAX_SEGMENT]; //1452 - 1471 //1FDF24C addr da SegmentListY na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D8528C - 1996 - 2015 - 0x7CC int SegmentWait[MAX_SEGMENT]; //1472 - 1491 //1FDF260 addr da SegmentWait na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D852A0 - 2016 - 2035 - 0x7E0 int SegmentDirection; //1492 - 1495 //1FDF274 addr da SegmentRange na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D852B4 - 2036 - 2039 - 0x7F4 int SegmentProgress; //1496 - 1499 //1FDF278 addr da SegmentDirection na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D852B8 - 2040 - 2043 - 0x7F8 int GenerateIndex; //1500 - 1503 //1FDF27C addr da GenerateIndex na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D852BC - 2044 - 2047 - 0x7FC unsigned short CurrentTarget; //1504 - 1505 //1FDF280 addr da CurrentTarget na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D852C0 - 2048 - 2049 - 0x800 unsigned short EnemyList[MAX_ENEMY]; //1506 - 1513 //1FDF282 addr da EnemyList na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D852C2 - 2050 - 2057 - 0x802 short PartyList[MAX_PARTY]; //1514 - 1537 //1FDF28A addr da PartyList na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D852CA - 2058 - 2081 - 0x80A short unk_1FDF2A2; //1538 - 1539 //1FDF2A2 int WeaponDamage; //1540 - 1543 //1FDF2A4 addr da WeaponDamage na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85334 - 2164 - 2167 - 0x874 int Summoner; //1544 - 1547 //1FDF2A8 addr da Summoner na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85338 - 2168 - 2171 - 0x878 int PotionCount; //1548 - 1551 //1FDF2AC addr da PotionCount na TMSrv 7.56 TMSrv 7.57 7D8533C - 2172 - 2175 - 0x87C int GuildDisable; //1552 - 1555 //1FDF2B0 addr da GuildDisable na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85340 - 2176 - 2179 - 0x880 int DropBonus; //1556 - 1559 //1FDF2B4 addr da DropBonus na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85344 - 2180 - 2183 - 0x884 int ExpBonus; //1560 - 1563 //1FDF2B8 addr da ExpBonus na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85348 - 2184 - 2187 - 0x888 int Range; //1564 - 1567 //1FDF2BC addr da Range na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D8534C - 2188 - 2191 - 0x88C int unk_1FDF2C0; //1568 - 1571 //1FDF2C0 TMSrv 7.57 7D85350 - 2192 - 2195 - 0x890 int unk_1FDF2C4; //1572 - 1575 //1FDF2C4 TMSrv 7.57 7D85354 - 2196 - 2199 - 0x894 int MobFace; //1576 - 1579 //1FDF2C8 addr da MobFace na TMSrv 7.56 - CORRETO - TMSrv 7.57 7D85358 - 2200 - 2203 - 0x898 //Calculo é feito com MobFace % 10 < 5 Mortal ou Transformações do BM retorna 0 //> 5 verifica no Learn se tem soul se nao tiver retorna 1 //se tiver soul retorna 2 int QuestFlag; //1580 - 1583 //1FDF2CC recebe o valor 0 na CreateMob - Relacionado com QUESTs TMSrv 7.57 7D8535C - 2204 - 2207 - 0x89C BOOL KhepraLive; //1588 - 1591 //1FDF2D4 - CORRETO - TMSrv 7.57 7D85360 - 2208 - 2211 - 0x8A0 int unk_1FDF2D8; //1592 - 1595 //1FDF2D8 - CORRETO - TMSrv 7.57 7D85364 - 2212 - 2215 - 0x8A4 int unk_1FDF2DC; //1596 - 1599 //1FDF2DC - CORRETO - TMSrv 7.57 7D85368 - 2212 - 2215 - 0x8A8 int unk_1FDF2E0; //1600 - 1603 //1FDF2E0 - CORRETO - TMSrv 7.57 7D8536C - 2212 - 2215 - 0x8AC int ServerKingdom; //1584 - 1587 //1FDF2D0 - CORRETO - TMSrv 7.57 7D85380 - 2236 - 2239 - 0x8BC int ForceDamage; //1604 - 1607 //1FDF2E4 - CORRETO - TMSrv 7.57 7D85370 - 2224 - 2227 - 0x8B0 int TmpSpeed; //1644 - 1647 //1FDF30C - CORRETO - TMSrv 7.57 7D85374 - 2228 - 2231 - 0x8B4 int CurTime; //1648 - 1651 //1FDF310 - CORRETO - TMSrv 7.57 7D85378 - 2232 - 2235 - 0x8B8 int unk_7D85384; //Descobrir o que é parece um timer TMSrv 7.57 7D85384 - 2240 - 2243 - 0x8C0 int CountHpDamage; //1608 - 1611 //1FDF2E8 - CORRETO - TMSrv 7.57 7D85398 - 2264 - 2267 - 0x8D8 int countHP; //1612 - 1615 //1FDF2EC - CORRETO - TMSrv 7.57 7D8539C - 2268 - 2271 - 0x8DC int countMP; //1616 - 1619 //1FDF2F0 - CORRETO - TMSrv 7.57 7D853A0 - 2272 - 2275 - 0x8E0 int PerfBonus; //1620 - 1623 //1FDF2F4 - CORRETO - TMSrv 7.57 7D853A4 - 2276 - 2279 - 0x8E4 int AbsBonus; //1624 - 1627 //1FDF2F8 - CORRETO - TMSrv 7.57 7D853A8 - 2280 - 2283 - 0x8E8 int unk_1FDF2FC; //1628 - 1631 //1FDF2FC TMSrv 7.57 7D853AC - 2284 - 2287 - 0x8EC int SummonType; //1632 - 1635 //1FDF300 - CORRETO - TMSrv 7.57 7D853B0 - 2288 - 2291 - 0x8F0 int ItemUser; //1636 - 1639 //1FDF304 - CORRETO - TMSrv 7.57 7D853B4 - 2292 - 2295 - 0x8F4 int ItemSummoner; //1640 - 1643 //1FDF308 - CORRETO - TMSrv 7.57 7D853B8 - 2296 - 2299 - 0x8F8 short DamagePvP; // - CORRETO - TMSrv 7.57 7D853BC - 2300 - 2301 - 0x8FC short DefensePvP; // - CORRETO - TMSrv 7.57 7D853BE - 2302 - 2303 - 0x8FE short MobList[MAX_PARTY]; // - CORRETO - TMSrv 7.57 7D853C0 - 2304 - 2327 - 0x900 Proximo é o nAffectInfo int unk_1FDF314; //1652 - 1655 //1FDF314 - CORRETO - int ServerTowerId; //1656 - 1659 //1FDF318 - CORRETO - char Tab[MAX_TAB_LENGTH]; //1660 - 1687 //1FDF31C - CORRETO - TMSrv 7.57 - 1928 - 1953 - 0x788 (1FDF334 -> MAX_TAB_LENGTH - 2 = 0) (1FDF335 -> MAX_TAB_LENGTH - 1 = 0) define o fim do buffer do Tab int unk_1FDF338; //1688 - 1691 //1FDF338 - CORRETO - int unk_1FDF33C; //1692 - 1695 //1FDF33C - CORRETO - TMSrv 7.57 7D85388 - Possivelmente um Count int unk_1FDF340; //1696 - 1699 //1FDF340 - CORRETO - Possivelmente uma PosX int unk_1FDF344; //1700 - 1703 //1FDF344 - CORRETO - Possivelmente uma PosY int unk_1FDF348; //1704 - 1707 //1FDF348 - CORRETO - int nAffectInfo; //1708 - 1711 //1FDF34C - CORRETO - TMSrv 7.57 7D853D8 - 2328 - 2331 - 0x918 /* //0 off - 1 on Bit 0 : Controle de Mana (1 << 0) Bit 1 : Imunidade (1 << 1) Bit 2 : Encantar Gelo (1 << 2) Bit 3 : Possuido (1 << 3) Bit 4 : Toxina da Serpente (1 << 4) Bit 5 : Evasão Aprimorada (1 << 5) Bit 6 : Invisibilidade (1 << 6) Bit 7 : Velocidade (1 << 7) Bit 8 : (1 << 8) Bit 9 : Cancel (1 << 9) Bit 10 : Congelado (1 << 10) Bit 11 : Invuneravel (1 << 11) Bit 12 : Flash (1 << 12) */ short nSkillDalay; //1712 - 1713 //1FDF350 - CORRETO - TMSrv 7.57 7D853DC - 2332 - 2333 - 0x91C int Accuracy; //1716 - 1719 //1FDF354 - CORRETO - TMSrv 7.57 7D853E0 - 2334 - 2337 - 0x91E int Evasion; //1720 - 1723 //1FDF358 - CORRETO - TMSrv 7.57 7D853E4 - 2338 - 2343 - 0x922 }; struct STRUCT_SUBCLASSINFO { unsigned int saveLearnedSkill; // 1FDF044 - CORRETO - TMSrv 7.57 7D84FF0 - - - - salva o Learn do celestial/subcelestial unsigned int saveNLearnedSkill; // 757+ - CORRETO - TMSrv 7.57 7D84FF4 - - - - salva o Learn2 do celestial/subcelestial STRUCT_ITEM saveFace; // 1FDF048 - CORRETO - TMSrv 7.57 7D84FF8 - - - - salva Face do personagem STRUCT_SCORE saveBaseScore; // 1FDF050 - CORRETO - TMSrv 7.57 7D85000 - - - - salva a BaseScore long long saveExp; // 1FDF06C - CORRETO - TMSrv 7.57 7D85030 - salva a Exp (int na 756-) char saveSkillBar[20]; // 1FDF070 - CORRETO - TMSrv 7.57 7D85038 - salva a SkilBar1[4] e a SkillBar2[16] unsigned short saveScoreBonus; // 1FDF084 - CORRETO - TMSrv 7.57 7D8504C - salva os pontos de Score que ainda nao foram distribuidos unsigned short saveSkillBonus; // 1FDF086 - CORRETO - TMSrv 7.57 7D8504E - salva os pontos para compra de skills }; enum AFFECT_INFO { EMPTY_AFFECT = 0, MANACONTROL = 1, IMMUNE = 2, FREEZE = 4, BERSERKER = 8, POISON = 16, EVASION = 32, INVISIBLE = 64, VELOCITY = 128, IMMUNITY = 256, CANCEL = 512, FROZEN = 1024, //757+ INVULNERABLE = 2048, //757+ FLASH = 4096 //757+ }; int CMob::StandingByProcessor() //Função Ok { int rt = FALSE; //local 2 ebp-08 local 5 if (MOB.CurrentScore.MaxMp) { if (MOB.CurrentScore.Mp <= 0 && Mode != MOB_COMBAT) { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } //0041724B - 004CCC8B MOB.CurrentScore.Mp--; } //0041725D - 004CCC9A int Face = MOB.Equip[FACE].Index; //local 3 ebp-0c local 8 if (Affect[0].Type != 24 && Face == 358) //Vinha { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } //00417291 - 004CCCD5 if (RouteType == 5) { if (Leader <= MOB_EMPTY || Leader >= MAX_USER) { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } //004172CD - 004CCD10 int otherFace = MOB.Equip[FACE].Index; //local 4 ebp-10 local 11 if (Affect[0].Type != 24 && (otherFace < 315 || otherFace > 346)) { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } //0041730A - 004CCD51 int summoner = Summoner; //local 5 ebp-14 local 14 if (summoner <= MOB_EMPTY || summoner >= MAX_USER) { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } //00417336 - 004CCD84 int isLeader = FALSE; //local 6 ebp-18 local 17 if (Leader == summoner) isLeader = TRUE; for (int i = 0; i < MAX_PARTY; ++i) //local 7 ebp-1c local 20 { if (pMob[Leader].PartyList[i] == summoner) isLeader = TRUE; } //00417392 - 004CCDE0 if (!isLeader) { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } //004173A9 - 004CCDF9 if (Affect[0].Type == 24 && !Affect[0].Time) { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } //004173D6 - 004CCE27 if (pUser[summoner].Mode == USER_PLAY) { int Distance = BASE_GetDistance(TargetX, TargetY, pMob[summoner].TargetX, pMob[summoner].TargetY); //local 8 ebp-20 local 23 if (Distance >= 20) { NextX = pMob[summoner].TargetX; NextY = pMob[summoner].TargetY; rt |= 2; return rt; } //00417472 - 004CCEC5 if (Distance > 2 && Distance < 20) { SegmentX = pMob[summoner].TargetX; SegmentY = pMob[summoner].TargetY; GetNextPos(0); rt |= 1; return rt; } } //004174CA - 004CCF1C else { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } //004174DB - 004CCF2F return rt; } //004174E3 - 004CCF37 if (!Leader) { int target = GetEnemyFromView(); //local 9 ebp-24 local 26 if (target && TargetX < (SegmentX + 12) && TargetX > (SegmentX - 12) && TargetY < (SegmentY + 12) && TargetY > (SegmentY - 12)) { target |= 0x10000000; return target; } } //00417569 - 004CCFBD if (RouteType == 6 && TargetX == SegmentX && TargetY == SegmentY) return 0; //004175A4 - 004CCFF8 if (SegmentX == TargetX && SegmentY == TargetY) { //004175F4 - 004CD028 if(WaitSec > 0 && RouteType != 6) { WaitSec -= 6; if (WaitSec > 0) { if (!RouteType && TargetX == SegmentListX[0] && TargetY == SegmentListY[0]) return 0; //00417650 - 004CD0A4 if (!(MOB.BaseScore.AttackRun & 0xF)) return 0; #ifdef CLIVER756- rt |= 16; #else rt |= 4096; //7.57+ #endif return rt; } //00417677 - 004CD0CA WaitSec = 0; } else //00417686 - 004CD0D9 { int SegWait = SegmentWait[SegmentProgress]; //local 10 ebp-28 local 29 if (SegWait > 0) { WaitSec = SegWait; return rt; } } //004176B3 - 004CD106 int setSeg = SetSegment(); //local 11 ebp-2c local 32 if (setSeg == 1) return rt; //004176C9 - 004CD11C if (setSeg == 2) { #ifdef CLIVER756- rt |= 1; #else rt |= 256; //7.57+ #endif return rt; } } //004176DD - 004CD132 GetNextPos(0); if (NextX == TargetX && NextY == TargetY) { SetSegment(); return rt; } rt |= 1; return rt; } //00417890 addr da BattleProcessor na TMSrv 7.56 - TMSrv 7.57 004CD190 int CMob::BattleProcessor() //Função Ok { int Face = MOB.Equip[FACE].Index; //local 2 ebp-08 local 5 if (Affect[0].Type != 24 && Face == 358) //vinha return 32; //004178E0 - 004CD1E2 SelectTargetFromEnemyList(); if (CurrentTarget == MOB_EMPTY) { Mode = MOB_PEACE; return 0; } //0041790A - 004CD20C if (RouteType == 5) { if (Leader <= MOB_EMPTY || Leader >= MAX_USER) return 32; int SummonerId = Summoner; //local 3 ebp-0c local 8 if (SummonerId <= MOB_EMPTY || SummonerId >= MAX_USER) return 32; int HP = MOB.CurrentScore.Hp; //local 4 ebp-10 local 11 if (HP <= 0) return 32; //00417989 - 004CD288 if (Affect[0].Type != 24 && (Face < 315 || Face > 346)) return 32; //004179B5 - 004CD2B3 int Summoned = FALSE; //local 5 ebp-14 local 14 if (Leader == SummonerId) Summoned = TRUE; //004179D1 - 004CD2CF for (int i = 0; i < MAX_PARTY; i++) //local 6 ebp-18 local 17 { if (pMob[Leader].PartyList[i] == SummonerId) Summoned = TRUE; } if (!Summoned) return 32; //00417A21 - 004CD31F int Distance = BASE_GetDistance(TargetX, TargetY, pMob[SummonerId].TargetX, pMob[SummonerId].TargetY); //local 7 ebp-1c local 20 if (Distance >= 20) { NextX = pMob[SummonerId].TargetX; NextY = pMob[SummonerId].TargetY; return 2; } } //00417AA0 - 004CD39E int Int = MOB.BaseScore.Int; //local 8 ebp-20 local 23 ebp-5c if (Int < rand() % 100) return 0x10000; //00417AC6 - 004CD3C4 int Dex = MOB.BaseScore.Dex; //local 9 ebp-24 local 26 ebp-68 int posX = pMob[CurrentTarget].TargetX; //local 10 ebp-28 local 29 ebp-74 int posY = pMob[CurrentTarget].TargetY; //local 11 ebp-2c local 32 ebp-80 int Range = BASE_GetMobAbility(&MOB, EF_RANGE); //local 12 ebp-30 local 35 ebp-8c int Distance = BASE_GetDistance(TargetX, TargetY, posX, posY); //local 13 ebp-34 local 38 ebp-98 //00417B3A - 004CD43E if (CheckKhepra()) Range = 26; //00417B4D - 004CD454 if (pMob[CurrentTarget].CheckKhepra() && (Face == 307 || Face == 245)) Range = 26; //00417B85 - 004CD48F if (RouteType != 5) { if(TargetX > (SegmentX + 30) || TargetX < (SegmentX - 30) || TargetY > (SegmentY + 30) || TargetY < (SegmentY - 30)) { //004CD4FF //7.57+ esse if é somente da 7.57 para frente if (unk_1FDF2D8 != 0) //0x8A4 - identificar o que é essa variavel na 7.57 { if (CurrentTarget == MOB_EMPTY) { for (int i = MOB_EMPTY; i < MAX_ENEMY; i++) //local 41 EnemyList[i] = MOB_EMPTY; //004CD556 Mode = MOB_PEACE; NextX = SegmentListX[0]; NextY = SegmentListY[0]; return 2; } } //00417BF5 - 004CD596 else //7.56 retirar o if e deixar so o conteudo do else { CurrentTarget = MOB_EMPTY; for (int i = MOB_EMPTY; i < MAX_ENEMY; i++) //local 14 ebp-38 local 44 EnemyList[i] = MOB_EMPTY; Mode = MOB_PEACE; GetNextPos(1); if (NextX == TargetX && NextY == TargetY) return 0; else return 16; } } } //00417C7B - 004CD629 if (Distance <= Range) { int _rand = rand() % 100; //local 15 ebp-3c ebp-0bc if (Range >= 4 && Distance <= 2 && _rand > Dex && MOB.BaseScore.AttackRun & 0xF) return 256; //00417CC4 - 004CD681 int _X = posX; //local 16 ebp-40 ebp-0c8 int _Y = posY; //local 17 ebp-44 ebp-0d4 int maxDist = SECBATTLE; //local 18 ebp-48 ebp-0e0 //00417CD7 - 004CD69D if (!CheckKhepra()) { int isHall = FALSE; //local 19 ebp-4c ebp-0ec if (TargetX >= 2341 && TargetX <= 2393 && TargetY >= 3907 && TargetY <= 3954 && unk_1FDF300) isHall = TRUE; //00417D3D - 004CD709 if (!isHall) BASE_GetHitPosition(TargetX, TargetY, &posX, &posY, (char*)pHeightGrid, maxDist); } //00417D70 - 004CD742 if (posX != _X || posY != _Y) return 256; else return 4096; } //00417D8E - 004CD768 return 1; }
    1 ponto
  27. @ 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.
    1 ponto
  28. Fala, pessoal. Queria compartilhar com vocês esse repositório do WYD FieldScene Studio Pro. Mesmo não sendo programador, o trabalho do Hamilton me inspirou bastante. A base do projeto e toda a ideia inicial me chamaram atenção justamente pelo quanto essa ferramenta veio pra ajudar quem mexe com interface e edição de painéis no WYD. Sem exagero algum, eu cheguei em 90 versoes em testes "ta comm tempo né" kkk A partir disso, tive a ideia de tentar tornar o programa mais acessível, principalmente para quem não tem monitor com resolução muito alta ou acaba sofrendo com a limitação de espaço na tela durante a edição. Além disso, fui buscando implementar melhorias de usabilidade, organização visual e praticidade no fluxo de trabalho, sempre tentando deixar a ferramenta mais confortável e funcional no uso do dia a dia. O objetivo não foi apagar a origem do projeto, mas sim evoluir em cima de uma base que já era boa, trazendo adaptações, correções e recursos que pudessem facilitar a vida de mais pessoas. Entre os pontos que busquei melhorar estão: - melhor adaptação para diferentes resoluções - visualização em escala 1:1 - conversão e ajuste entre resoluções - carregamento e compatibilidade de recursos - melhorias no uso geral do editor - remoção de fundo em imagens compatíveis - mais praticidade para edição, importação e visualização -o programa tem régua -arraste por mouse **OBS IMPORTANTE, É RECOMENDADO QUE QUANDO FOR SOLICITADO O CARREGAMENTO DE RECURSOS ABRA ATÉ A PASTA DO CLIENTE ONDE ESTÃO AS PASTAS UI, NUI E MESH, ASSIM O PROGRRAMA JÁ CARREGA AS 3 PASTAS NO LUGGAR DE ABRIR UMA POR VEZ, ALGUNS PAINEIS AS VEZES ESTAO FORA DA UI** e mais coisas que não me lembro agora haha Estou compartilhando porque pode ser útil para outras pessoas da área, e também porque acho justo reconhecer que essa iniciativa só existiu porque o trabalho original me motivou a tentar fazer algo também Repositório: [Hidden Content] Se alguém quiser testar, dar feedback ou sugerir melhorias, vai ser muito bem-vindo. E LEMBRANDDO CRÉDITOS TOTAIS AO HAMILTON DO CANAL HC CURSOS E TUTORIAIS
    1 ponto
  29. Há muito tempo, desenvolvi este editor, mas ele estava desatualizado. Agora, estou compartilhando a versão mais recente, atualizada com a última atualização do WYD Global, v763 (15/03/2025). Atualização 16/03/2025: Foi adicionado suporte para versão 759,763 e 769. Foi adicionado a exibição de ícones. Atualização 19/03/2025: Foi adicionado suporte para ExtraItem.bin para aqueles que não sabem todo item da itemlist que estiver dentro da extraitem.bin será substituído pelo mesmo. Download:
    1 ponto
  30. 1 ponto
  31. 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
  32. Alguém consegue o login desse site [Hidden Content]
    1 ponto
  33. 🔥 INSIGHT CHEATS - POINT BLANK BRASIL 🔥 (Atualizado em 13/11/2025) 💎 Estamos há 3 anos sem nenhum banimento por detecção do loader! 💎 🚀 FUNCIONALIDADES INCRÍVEIS 🔍 ESP's: Visualize inimigos através das paredes! Inclui Boxes, Esqueleto, Linhas, Nomes, Distância e muito mais. 🎯 Aimbot: • Silent: Muda a trajetória do tiro diretamente para o inimigo. • CrossHair: Puxa a mira até o inimigo automaticamente. 🧠 Aim FOV: Define a área de atuação do Aimbot. 👀 Visible Check: A mira trava apenas em inimigos visíveis. 🛡️ Anti Vote Kick: Previne que você seja expulso da partida por votação. 🖥️ FullScreen Mode: Ativa o modo tela cheia do jogo automaticamente. ⚡ FPS Ilimitado: Remove limites de FPS, garantindo o máximo desempenho! 🎯 Anti Helmet Protection: Inimigos não recebem proteção de capacete, mesmo com boina ou máscara. 📺 Stream Mode: Oculta menus e ESPs em transmissões no OBS Studio. 🔫 TriggerBot: Disparo automático ao detectar inimigo na mira. ⚡ Fast Quick Weapon: Reduz em 50% o tempo de troca de arma (simula item "Troca Rápida"). 🔄 Fast Reload Reduction: Reduz em 50% o tempo de recarga (simula item "Recarregamento Rápido"). E muito mais opções! 🎮 INSIGHT MENU VIP DEMONSTRAÇÃO 🎮 🛒 TUTORIAL DE COMPRA - PASSO A PASSO 🛒 SITE PARA COMPRAS - INSIGHT CHEATS COMPRE CLICANDO AQUI!
    1 ponto
  34. 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
  35. Alguem consegue o login desse [Hidden Content]
    1 ponto
  36. ASSINATURAS ATUALIZADAS Patrocinadora: streamingsbarato.com [Hidden Content] [Hidden Content] [Hidden Content] [Hidden Content] Assinatura será atualizada todos os meses.
    1 ponto
  37. 1 ponto
  38. O link do drive está pedindo solicitação para o acesso! Peço que corrija. @ userweedd [Hidden Content]
    1 ponto
  39. Fala pessoal blz? estou entrando de ferias da oficina e vou dar uma focada no meu emulador novamente, entao refiz o sistema de log padrao e vou disponibilizar aqui caso alguem tenha interesse em usar ou melhorar. Segue o link do Projeto: GitHub GuiCan na main tem uma implementação simples so para teste e poderem ver como funciona. ficou bem bacana pode ser expandida conforme a necessidade e aprimorada tem sistema de rotação de logs quando chega ao tamanha maximo do arquivo depois de X dias os arquivos sao zipados e se tiver configurado pode ser feito upload para algum servidor ftp se sua escolha para guardar backups apos X dias os logs antigos sao removidos. basicamente é isso.
    1 ponto
  40. 1 ponto
  41. Pack com vídeos da Letícia Reed. Basta curtir o tópico para revelar o conteúdo. [hide][Hidden Content]]
    1 ponto
  42. Bom, já que postaram o conteudo incompleto e nem todos tem o client, source e release, estarei postando os arquivos completinhos pra vocês, façam bom uso e estudem bastante, pois nessa source possui bastante bugs! Tudo que fazemos volta para nós nessa vida. Release Source Client Scan Release Scan Source Scan Client
    1 ponto
  43. Contas Xbox | Algumas com Game Pass Ultimate [Hidden Content] SEJA UM VIP EXTREME Acesso à Área VIP com alguns conteúdos exclusivos: Canva PRO, PrimeVídeo e Engajamento Rede Social. VIP EXTREME Doador Comunidade Emblema Selo de Verificado nos Comentários Seu Username com Efeito Seu Username com a Cor Vermelha Um cargo TeamIcon Exclusiva VIP Extreme Animado Todos seus Comentários destacados com Borda Vermelha Direito de Trocar Nickname Gratuitamente apenas uma única vez Acesso à Área VIP com alguns conteúdos exclusivos: Canva PRO, PrimeVídeo e Engajamento Rede Social. Poder Moderativo: Visualizar Mensagens Ocultas/Desaprovadas pela Moderação ADQUIRA SEU VIP AGORA MESMO:
    1 ponto
  44. [Hidden Content] Bom proveito.
    1 ponto
  45. 📝 Descrição: 🔥 E aí, guerreiro(a)! Pronto para DOMINAR a criação de servidores WYD? Neste vídeo 100% COMPLETO, você vai aprender passo a passo como compilar, configurar e deixar seu servidor WYD funcionando perfeitamente! 🌐💻 🔹 O que você vai dominar? ✅ Configurar IP e portas corretamente ✅ Ajustar o client para seus jogadores ✅ Compilar a source sem erros ✅ Liberar o server release como um PRO ✅ Configurar Release ✅ Compilar Sourcer do Servidor e Cliente ✅ + Dicas exclusivas para evitar erros comuns! ( Todos os links na descrição do vídeo no Youtube ) 1️⃣ SERVIDOR PRIVADO 🔓 WYD 7.59 LIBERADO! (Download Direto Exclusivo) 🚀 2️⃣ Como MUDAR a SENHA 🔑 do MySQL no phpMyAdmin (XAMPP) – Tutorial RÁPIDO e FÁCIL! ⚡ 3️⃣ COMO COLOCAR SEU SERVIDOR DE WYD ONLINE! 🔥 (Rede Local, VPN, VPS e Ngrok) ⚡ 👉 Seja um MESTRE dos servidores WYD! Deixe seu LIKE ❤️, INSCREVA-SE 🔔 e compartilhe com a galera! 💬 Ficou com dúvida? Pergunta nos comentários que a gente responde! � [hide][Hidden Content]]
    1 ponto
  46. 📢 [DOAÇÃO] Contas HBO Max – Grátis e Funcionando! 🎁 Olá, galera! Estou distribuindo contas HBO Max ativas, prontas para usar – sem custo algum. Isso mesmo: totalmente grátis! 😍 🎬 Se você curte maratonar séries, filmes, documentários e lançamentos, essa é a sua chance de aproveitar tudo que o HBO Max oferece, incluindo: 🔥 House of the Dragon 🧟 The Last of Us 🦇 Batman 🧙 Saga Harry Potter 🎞️ E muito mais conteúdo exclusivo! ✅ Como funciona? Simples: estou enviando diretamente aqui no tópico. Basta ficar de olho e pegar a sua! 📌 Regras básicas: Não altere os dados da conta. Use com responsabilidade. Se a conta parar de funcionar, aguarde novas doações. 💬 Agradeça se pegar uma conta – isso incentiva mais doações no futuro! 🤝 Curta, comente e compartilhe com quem precisa! 📦 As contas estão logo abaixo. Boa maratona! 🍿💜 [Hidden Content] Scan
    1 ponto
  47. Fala galera, Bom como não to mais afim de mexer com WYD e com certeza alguem vai fazer algo de bom isso estou liberando essa source totalmente desbugada . Segue algumas informações: CONTÉM: - ANT-HACK E BLOQUEIO CONTRA RANGE, SPEED ENTRE OUTROS CASO ALGUEM CONSIGA INJETAR. - SISTEMA DE AGRUPAR E DPI POR COMANDO PORÉM PODE SER USADA EM FADA OU COMO QUISER - SISTEMA DE BOSS CONFIGURÁVEL NA SOURCE - SISTEMA PARA BALANCEAMENTO DE CLASSES NA SOURCE CASO DESEJE ALTERAR - SISTEMA DA PISTA DESBUGADOS - SISTEMA BATALHA REAL [CONFIGURAR PELA SOURCE] - SISTEMA INVASÃO ALEATÓRIA - DROP CONFIGURÁVEL PELA SOURCE TAMBÉM - SISTEMA DO ALTAR DE NOATUM - SISTEMA DE AJUDANTE COM ITEM DE UPAR O AJUDANTE, CONTÉM BM/FM/TK, CONFIGURÁVEIS NA SOURCE - VÁRIOS COMANDOS: [/agrupar , /boss , /droppvp, /armia, ...] - CLIENT COM INTERFACE CUSTOMIZADA - SITE COMPLETO COM CADASTRO E BANCO DE DADOS PARA FAZER O PAINEL TUDO MODIFICÁVEL - COMANDO /ativar VERIFICA A QUANTIDADE E DÁ PREMIAÇÃO AUTOMATICAMENTE, TUDO CONFIGURADO NA SOURCE. - SISTEMA DE GERAÇÃO AUTOMÁTICA DE PINCODE DO SITE PARA O JOGO, TAMBÉM CONFIGURÁVEL. - DOUBLE E PESCA AUTOMÁTICOS FINAIS DE DE SEMANA, LOCAL DA PESCA CONFIGURADA NA SOURCE. - HAVIA COMEÇADO A FAZER UM DROP LIST AUTOMÁTICO MAS NÃO ACABEI OS ARQUIVOS ESTÃO JUNTO COM O SITE Versão: 7.56 EXP: Media Drop: Media Conexão: 24/7 Rates Compositores: 40% Tutorial iniciante: NPC's Dando armas +frango +shire 3D ao nasce no campo de treino. -> CLASSES BALANCEADAS;-> SERVER CONTA COM SISTEMA PARA ADQUIRIR DONATE NO PAINEL LOCALIZADO NO SITE;-> PESCA ATIVA SO FINAL DE SEMANA AUTOMATICO;-> DOUBLE ATIVO SO FINAL DE SEMANA; SISTEMA DE PREMIAÇÃO DIÁRIA: TODOS OS DIAS USE: /resgatar PARA GANHAR UM DOS ITENS ABAIXO: ->10PL ->10P.O -> 20X POÇÃO VIGOR ->POÇÃO 20HORAS -> 100KK Sistema de Comandos: /armia = Teleporta para cidade de Armia /edpoints = Verifica Quantidade de Cash /honra =Verifica honra/evento =Teleporta para área do evento [Quando ativo]/senha = Define uma senha para o grupo/entrar = Entra no grupo de alguém /boss = Area de boss /droppvp = Area Pvp para DROP /resgatar = Resgata diariamente premios./translider= Transfere o grupo para algum membro/autogrupo = Ativa o auto grupo para todos jogadores/macro = Ativa macro de perga N/M/A/dpi = Filtro para dropar apenas oque você quer./dpiadd = adicionas as ID's do itens que apenas esses vão ser dorpados;obs.: Cuidado ao usar esse comando [/dpi e /dpiadd ] a equipe não devolvera itens dropados apagados por esse comando./agrupar = Você liga o auto agrupador/agruparadd = Você adiciona itens ao auto agrupador /agruparadd 413 no caso da poeira de lac do id 41 Sistema de Honra: EVENTO LOJINHA DANDO 1 DE HONRA A CADA 20 MIN VIDEO TUTO LOJA DE HONRA SISTEMA AJUDANTE SISTEMA DE AJUDANTE: ->USADO A PARTIR DO LEVEL 106; ->PODE SER USADO EM QUALQUER CLASSE; ->PODE SER EVOLUÍDO DO 0 AO LEVEL 255; ->ITEM EXCLUSIVO DE UP DO AJUDANTE; ->NÃO PODE SER USADO CONTRA KEFRA; ->AJUDANTE ATACA QUEM ATACAR AFK SEU CHAR ; -> CASO MORRA É SO DESEQUIPAR E EQUIPAR QUE VOLTA; ->AJUDA COM DROP/UP; ->PODE SER INVOCADO MAIS DE UM AJUDANTE NO GRUPO; -> SISTEMA PARA ADQUIRIR O UP AJUDANTE ESTÁ EM DESENVOLVIMENTO; VIDEO TUTO AJUDANTE ALGUMAS IMAGENS: ITEM DE UP DO AJUDANTE: SISTEMAS DE BOSS [Hidden Content] ---------------------------------------------------------------------------------- ARKAV DEMON ---------------------------------------------------------------------------------- Nasce nos horarios : HORA : 01 / 05 / 09 / 13 / 17 / 21 MINUTO: 30 Drop: ABS C/ ADD 2 % CRITICO OU 50 DEF OU 40 HP OU 40 MP OU NADA DE DROP Para ir até o boss bastar digitar /boss , cuidado área PvP ---------------------------------------------------------------------------------- INVASÃO DE MONSTROS ---------------------------------------------------------------------------------- Nasce nos horarios : HORA : 06 / 12 / 18 / 20 MINUTO: 00 Drop: 100% 100KK NO CEIFEIRO E 100% DROP PL SEG. CEIFEIRO NASCE DE FORMA ALEATÓRIA EM ALGUMA CIDADE [ARMIA, ERION, AZRAN, GELO E NOATUM] ---------------------------------------------------------------------------------- VERID ---------------------------------------------------------------------------------- Nasce nos horarios : HORA : 01 / 05 / 09 / 13 / 17 / 21 MINUTO: 00 Drop: ARMAS 63 /54 OU 28/24 OU NÃO DROPA NADA NASCE NA VILA AMALD, BASTA USAR O PERGAMINHO DE CAÇA DO GELO ---------------------------------------------------------------------------------- UP AUXILIAR ---------------------------------------------------------------------------------- Nasce nos horarios : HORA : 20 /23 MINUTO: 00 Drop: PAC COM 20 ITENS DE UP DO AUXILIAR NASCE 5 MOBS NA NOVA AREA DE DROP PVP, BASTA USAR /droppvp ---------------------------------------------------------------------------------- SOMBRA NEGRA ---------------------------------------------------------------------------------- Nasce nos horarios : HORA : A CADA 3 HORAS MINUTO: 00 Drop: LIVROS SEPHIRA BASTA USAR O PERGAMINHO DE CAÇA DO GELO E IR PROXIMO AS VALKIRIA Guerras RvR 18 horas Torre 22 Horas Batle Royal 18 Horas No mais é isso.
    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.