PIC Symphony
好的,我现在需要帮用户总结一篇文章的内容,控制在100字以内。首先,我得仔细阅读用户提供的文章内容,理解其主要信息。 文章主要讲的是Crystal Palace的更新,提到了两个新的命令:linkfunc和addhook。linkfunc用于将汇编代码合并到PICO中,解决了之前只能合并COFF文件的问题。而addhook增加了链式挂钩功能,允许为同一个API注册多个钩子,这样在某个方法失败时可以使用备用方法。 接下来,我需要将这些信息浓缩到100字以内。要注意直接描述内容,不需要开头语。所以我会先点明Crystal Palace的更新,然后分别简要介绍这两个新功能。 最后检查字数是否符合要求,并确保语言简洁明了。 </think> Raffi 更新了 Crystal Palace,新增 `linkfunc` 和 `addhook` 命令。`linkfunc` 解决了将汇编代码合并到 PICO 的问题;`addhook` 支持链式挂钩,允许为同一 API 注册多个钩子以实现备用机制。 2025-12-1 20:11:10 Author: rastamouse.me(查看原文) 阅读量:5 收藏

Raffi just released another update to Crystal Palace, which serves to improve the way specification files are handled by making them more modular.

Tradecraft Orchestration in the Garden

What’s more relaxing than a beautiful fall day, a crisp breeze, a glass of Sangria, and music from the local orchestra? Of course, I expect you answered: writing position-independent code projects …

Skip to content

I'm not going to go over the content of that post, as he does a good job at describing the changes. The purpose of this post is to cover two commands that were added/updated that were not addressed in the update blog.

linkfunc

I had previously tried to find an ergonomic way of integrating the Draugr call stack spoofing technique into both my Crystal Palace loader and hooking PICO. Since Crystal Palace is designed around weaving modular tradecraft, it makes sense (to me, anyway) to write this stub in pure assembly and build it with NASM.

draugr_stub:
    pop rax
    mov r10, rdi
    mov r11, rsi
    mov rdi, [ rsp + 32 ]
    mov rsi, [ rsp + 40 ]
    ...
$(NASM) src/draugr.asm -o bin/draugr.x64.bin

You can declare the function as an extern in the C code, and rely on linking the assembly to the symbol at link-time.

extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID );

Then load your various COFFs and merge them as needed in the spec file:

x64:
    load "bin/pico.x64.o"
        make object
    
        # merge the hook functions
        load "bin/hooks.x64.o"
            merge

        # merge the call stack spoofing
        load "bin/spoof.x64.o"
            merge

        # merge the assembly stub
        load "bin/draugr.x64.bin"
            merge

        ...

Except this doesn't work because the merge command only works on COFF content, not raw assembly, so this will produce an error like: [-] COFF starts with unrecognized Machine value 0x4958 in pico.spec (x64).

Using link works ok when it's merged into a loader, because all of that memory is going to be RX or RWX. However, it's problematic for PICOs because link always puts stuff in the data section, which is likely to be loaded into RW memory. So you either need to make the PICO memory RWX; or RX and accept that you'll have no writeable data; or do some other gymnastics in the loader to load the stub separately and give it to the PICO via an import command.

All of these are obviously suboptimal.

The new linkfunc command instantly solves this issue, as it throws the given data into the code section of the PIC/PICO.

# merge the asm stub
load "bin/draugr.x64.bin"
    linkfunc "draugr_stub"

addhook

The syntax for the addhook command in the previous release was addhook "MODULE$Function" "hook", which would IAT hook the target function in a capability and redirect execution to the hook function. This command now has a new mode of usage, which is just addhook "MODULE$Function. This registers an attach "MODULE$Function" "hook" chain with the __resolve_hook() intrinsic.

A funky feature of attach is that you can chain multiple hooks for the same API. A good use case for this is if you implement evasion tradecraft that ends up failing, and you need one or more fallbacks. Here's a pseudo-code example:

BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect )
{
    /* try calling NtProtectVirtualMemory with an indirect syscall */
    NTSTATUS status = ...;

    if ( NT_SUCCESS ( status ) )
    {
        /* return result if successful */
        return result;
    }

    /* otherwise try the next technique */
    return KERNEL32$VirtualProtect ( lpAddress, dwSize, flNewProtect, lpflOldProtect );
}

BOOL WINAPI _VirtualProtect2 ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect )
{
    /* try calling VirtualProtect with call stack spoofing */
    BOOL success = ...;

    if ( success )
    {
        /* return result if successful */
        return result;
    }

    /* try the next technique */
    return KERNEL32$VirtualProtect ( lpAddress, dwSize, flNewProtect, lpflOldProtect );
}

BOOL WINAPI _VirtualProtect3 ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect )
{
    /* we give up, just call the original */
    return KERNEL32$VirtualProtect ( lpAddress, dwSize, flNewProtect, lpflOldProtect );
}

And chain the three hooks in the spec file:

attach "KERNEL32$VirtualProtect" "_VirtualProtect"  # hook VirtualProtect
attach "KERNEL32$VirtualProtect" "_VirtualProtect2" # stack a 2nd hook
attach "KERNEL32$VirtualProtect" "_VirtualProtect3" # stack a 3rd hook

This chain will only apply to VirtualProtect calls that the PIC makes, but adding addhook KERNEL32$VirtualProtect to the spec file would also apply this chain to any VirtualProtect calls that the hooked capability makes.

It's very cool 😎


文章来源: https://rastamouse.me/pic-symphony/
如有侵权请联系:admin#unsafe.sh