SbSelectProcedure

Go to Home Page

Picks the best matching function from a list based on the supportedOS guids in the manifest

Syntax

FARPROC WINAPI SbSelectProcedure (
    ULONG signature,
    ULONG unk,
    const SWITCHBRANCH_SCENARIO_TABLE* pScenarioTable,
    ULONG scenarioIndex
)

Parameters

signature
The value 0xABABABAB
unk
Unknown. Always set to 1
pScenarioTable
The table describing the various scenarios in this module
scenarioIndex
Which scenario in the table to pick the function for

Return Value

The best matching function or NULL on failure

Remarks

All instances of usage of this function use the signature value 0xABABABAB, but this value is actually ignored

The Sb in the function name stands for SwitchBack which is the name of this technology, but the symbols for the structures used in support of it are named SwitchBranch

There are numerous support structures required in addition to the third argument, these are defined as:

// branch details in a table entry should be ordered from the highest windows compatability manifest version 
// that makes sense to the lowest. So the win10 branch first, then win8.1, then win8, etc
//
// You can skip any you'd like e.g. only have entries for Win10 then Win7 without any others 

typedef PVOID (NTAPI*pfnBranchFunc)(PVOID);

typedef struct _SWITCHBRANCH_BRANCH_DETAILS
{
    PCSTR pSpecificName; // the name of this branch
    pfnBranchFunc pBranch; 
    ULONG unk; // always 1
    // 4-byte paadding on x64
    PCSTR pDescription;
    ULONG unk2; // 
    ULONG unk3; // always 0
    ULONG unk4; // always 1
    ULONG unk5; // always 0
    // the windows compatability guid specified in the manifest
    // that results in this branch being taken
    GUID windowsCompatGuid;
    // an id for this branch
    GUID branchGuid;
} SWITCHBRANCH_BRANCH_DETAILS, *PSWITCHBRANCH_BRANCH_DETAILS;

typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRY
{
    PCSTR pBranchName;
    PCSTR pBranchDescription;
    PCSTR pBranchReason;
    ULONG unk; // always 1
    ULONG unk2; // always 0
    ULONG unk3; // always 0
    ULONG unk4; // always 1
    ULONG unk5; // always 0
    GUID scenarioGuid;
    ULONG numScenarioBranches;
    SWITCHBRANCH_BRANCH_DETAILS branches[ANYSIZE_ARRAY]; // numScenarioBranches long
} SWITCHBRANCH_SCENARIO_TABLE_ENTRY, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRY;

typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRIES
{
    ULONG numScenarios;
    SWITCHBRANCH_SCENARIO_TABLE_ENTRY* pEntries[ANYSIZE_ARRAY]; // numScenarios long
} SWITCHBRANCH_SCENARIO_TABLE_ENTRIES, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRIES;

typedef struct _SWITCHBRANCH_CACHED_MODULE_TABLE
{
    ULONG64 changeCount;
    ULONG unk;
    ULONG numScenarios;
    PVOID pScenarios[ANYSIZE_ARRAY]; // numScenarios in size
} SWITCHBRANCH_CACHED_MODULE_TABLE, *PSWITCHBRANCH_CACHED_MODULE_TABLE;

typedef PVOID (WINAPI*pfnFilterFunc)(PVOID);

typedef struct _SWITCHBRANCH_SCENARIO_TABLE
{
    ULONG tag; // always 'EsLk', not ever checked even on checked builds
    ULONG unk; // Always 0x1000000
    SWITCHBRANCH_CACHED_MODULE_TABLE* pModuleTable;
    PVOID unk2; // always 0
    SWITCHBRANCH_SCENARIO_TABLE_ENTRIES* pScenarios;
    // this function probably has greater significance, but all occurances just return a string like
    // SbFilterProcedure_DdrawNamespace,
    // SbFilterProcedure_Scenario etc
    pfnFilterFunc filterProcedure;
} SWITCHBRANCH_SCENARIO_TABLE, *PSWITCHBRANCH_SCENARIO_TABLE;

Example

// This example hardcodes two scenarios with two branches each
// 
// It also demonstrates the complexities of using these functions 
// and the variable size arrays with static data
// All uses of this in Windows' dll's use static data
// so we are. Defining everything inline like this
// and using hardcoded dimensions for the variable sized
// arrays are the only way to make this compile
 
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0600
#include 
#include 

typedef PVOID (NTAPI*pfnBranchFunc)(PVOID);

// these are the compatibility manifest guids 
// {e2011457-1546-43c5-a5fe-008deee3d3f0}
// DEFINE_GUID(COMPAT_Vista, 0xe2011457, 0x1546, 0x43c5, 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0);
#define COMPAT_Vista {{0xe2011457}, {0x1546}, {0x43c5}, {0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0}}
// {35138b9a-5d96-4fbd-8e2d-a2440225f93a}
// DEFINE_GUID(COMPAT_Win7, 0x35138b9a, 0x5d96, 0x4fbd, 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a);
#define COMPAT_Win7  {{0x35138b9a}, {0x5d96}, {0x4fbd}, {0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a}}
// {4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}
// DEFINE_GUID(COMPAT_Win8, 0x4a2f28e3, 0x53b9, 0x4441, 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38);
#define COMPAT_Win8 {{0x4a2f28e3}, {0x53b9}, {0x4441}, {0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38}}
// {1f676c76-80e1-4239-95bb-83d0f6d0da78}
// DEFINE_GUID(COMPAT_Win81, 0x1f676c76, 0x80e1, 0x4239, 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78);
#define COMPAT_Win81 {{0x1f676c76}, {0x80e1}, {0x4239}, {0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78}}
// {8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}
// DEFINE_GUID(COMPAT_Win10, 0x8e0f7a12, 0xbfb3, 0x4fe8, 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a);
#define COMPAT_Win10 {{0x8e0f7a12}, {0xbfb3}, {0x4fe8}, {0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a}}

// branch details should be ordered from the highest windows compatability manifest version that makes sense
// to the lowest. So the win10 branch first, then win8.1, then win8, etc
typedef struct _SWITCHBRANCH_BRANCH_DETAILS
{
    PCSTR pSpecificName;
    pfnBranchFunc pBranch;
    ULONG unk; // always 1 (enabled?)
    // ULONG x64 padding
    PCSTR pDescription;
    ULONG unk2;
    ULONG unk3; // always 0
    ULONG unk4; // always 1
    ULONG unk5; // always 0
    // the windows compatability guid specified in the manifest
    // that results in this branch being taken
    GUID windowsCompatGuid;
    GUID branchGuid;
} SWITCHBRANCH_BRANCH_DETAILS, *PSWITCHBRANCH_BRANCH_DETAILS;

typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRY
{
    PCSTR pBranchName;
    PCSTR pBranchDescription;
    PCSTR pBranchReason;
    ULONG unk; // always 1
    ULONG unk2; // always 0
    ULONG unk3; // always 0
    ULONG unk4; // always 1
    ULONG unk5; // always 0
    GUID scenarioGuid;
    ULONG numScenarioBranches;
    SWITCHBRANCH_BRANCH_DETAILS branches[2]; // numScenarioBranches long
} SWITCHBRANCH_SCENARIO_TABLE_ENTRY, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRY;

//typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRIES
//{
//    ULONG numScenarios;
//    SWITCHBRANCH_SCENARIO_TABLE_ENTRY entries[2];
//} SWITCHBRANCH_SCENARIO_TABLE_ENTRIES, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRIES;

typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRIES
{
    ULONG numScenarios;
    SWITCHBRANCH_SCENARIO_TABLE_ENTRY* pEntries[2];
} SWITCHBRANCH_SCENARIO_TABLE_ENTRIES, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRIES;

typedef struct _SWITCHBRANCH_CACHED_MODULE_TABLE
{
    ULONG64 changeCount;
    ULONG unk;
    ULONG numScenarios;
    PVOID pScenarios[2]; // numScenarios in size
} SWITCHBRANCH_CACHED_MODULE_TABLE, *PSWITCHBRANCH_CACHED_MODULE_TABLE;

typedef PVOID (NTAPI*pfnFilterFunc)(PVOID);

typedef struct _SWITCHBRANCH_SCENARIO_TABLE
{
    ULONG tag; // always 'EsLk'
    ULONG unk; // version? Always 0x1000000
    SWITCHBRANCH_CACHED_MODULE_TABLE* pModuleTable;
    PVOID unk2; // always 0
    SWITCHBRANCH_SCENARIO_TABLE_ENTRIES* pScenarios;
    // this function probably has greater significance, but all occurances just return a string like
    // SbFilterProcedure_DdrawNamespace,
    // SbFilterProcedure_Scenario etc
    pfnFilterFunc filterProcedure;
} SWITCHBRANCH_SCENARIO_TABLE, *PSWITCHBRANCH_SCENARIO_TABLE;

#ifdef __cplusplus
extern "C"
{
#endif
NTSYSAPI
FARPROC //returns which function should be called
NTAPI
SbSelectProcedure(
    ULONG signature, // always 0xABABABAB
    ULONG p2, // always 1
    const SWITCHBRANCH_SCENARIO_TABLE* pScenarioInfo, 
    ULONG scenarioEntry // which scenario in the table the selection is for
);

NTSYSAPI
PVOID //returns the return value of the called function
NTAPI
SbExecuteProcedure(
    ULONG signature, // always 0xABABABAB
    ULONG p2, // always 1
    const SWITCHBRANCH_SCENARIO_TABLE* pScenarioInfo, 
    ULONG scenarioEntry, // which scenario in the table the selection is for
    PVOID pCtx // value passed to the selected procedure
);
#ifdef __cplusplus
}
#endif

// {17E5E81C-7D73-485b-9E8F-A3B2BB38594C}
// DEFINE_GUID(GUID_NumberScenario, 0x17e5e81c, 0x7d73, 0x485b, 0x9e, 0x8f, 0xa3, 0xb2, 0xbb, 0x38, 0x59, 0x4c);
#define GUID_NumberScenario {{0x17e5e81c}, {0x7d73}, {0x485b}, {0x9e, 0x8f, 0xa3, 0xb2, 0xbb, 0x38, 0x59, 0x4c}}
// {DC7DA31C-EEF6-4310-8514-5367D3742EAD}
// DEFINE_GUID(GUID_WordScenario, 0xdc7da31c, 0xeef6, 0x4310, 0x85, 0x14, 0x53, 0x67, 0xd3, 0x74, 0x2e, 0xad);
#define GUID_WordScenario {{0xdc7da31c}, {0xeef6}, {0x4310}, {0x85, 0x14, 0x53, 0x67, 0xd3, 0x74, 0x2e, 0xad}}

// {E70DA35B-C0D3-4496-A93B-7DCB20377E6A}
// DEFINE_GUID(BRANCH_NumVista, 0xe70da35b, 0xc0d3, 0x4496, 0xa9, 0x3b, 0x7d, 0xcb, 0x20, 0x37, 0x7e, 0x6a);
#define BRANCH_NumVista {{0xe70da35b}, {0xc0d3}, {0x4496}, {0xa9, 0x3b, 0x7d, 0xcb, 0x20, 0x37, 0x7e, 0x6a}}
// {2082D2B2-E758-48e8-9F2A-974D4753F04C}
// DEFINE_GUID(BRANCH_Num7, 0x2082d2b2, 0xe758, 0x48e8, 0x9f, 0x2a, 0x97, 0x4d, 0x47, 0x53, 0xf0, 0x4c);
#define BRANCH_Num7 {{0x2082d2b2}, {0xe758}, {0x48e8}, {0x9f, 0x2a, 0x97, 0x4d, 0x47, 0x53, 0xf0, 0x4c}}

// {FABAB681-60F4-4cd7-A405-6126F4CFA49B}
// DEFINE_GUID(BRANCH_WordVista, 0xfabab681, 0x60f4, 0x4cd7, 0xa4, 0x5, 0x61, 0x26, 0xf4, 0xcf, 0xa4, 0x9b);
#define BRANCH_WordVista {{0xfabab681}, {0x60f4}, {0x4cd7}, {0xa4, 0x5, 0x61, 0x26, 0xf4, 0xcf, 0xa4, 0x9b}}
// {AE6D3F34-DA55-4470-AA72-29DEE48C9AF9}
// DEFINE_GUID(BRANCH_Word7, 0xae6d3f34, 0xda55, 0x4470, 0xaa, 0x72, 0x29, 0xde, 0xe4, 0x8c, 0x9a, 0xf9);
#define BRANCH_Word7 {{0xae6d3f34}, {0xda55}, {0x4470}, {0xaa, 0x72, 0x29, 0xde, 0xe4, 0x8c, 0x9a, 0xf9}}


PVOID NTAPI NumBranchForVista(PVOID);
PVOID NTAPI NumBranchFor7(PVOID);
PVOID NTAPI WordBranchForVista(PVOID);
PVOID NTAPI WordBranchFor7(PVOID);

#define NUM_BRANCH_DETAIL_VISTA {"Vista Num Branch", &NumBranchForVista, 0, "Sets the flag to 0, because we hate Vista", 1, 0, 1, 0, COMPAT_Vista, BRANCH_NumVista}
#define NUM_BRANCH_DETAIL_7 {"7 Num Branch", &NumBranchFor7, 0, "Sets the flag to 1, because we like 7", 1, 0, 1, 0, COMPAT_Win7, BRANCH_Num7}

#define WORD_BRANCH_DETAIL_VISTA {"Vista Word Branch", &WordBranchForVista, 0, "Sets the word to No, because we hate Vista", 1, 0, 1, 0, COMPAT_Vista, BRANCH_WordVista}
#define WORD_BRANCH_DETAIL_7 {"7 Word Branch", &WordBranchFor7, 1, "Sets the word to Yes, because we like 7", 1, 0, 1, 0, COMPAT_Win7, BRANCH_Word7}

#define DIFF_NUM_SCENARIO \
    { \
        "DiffNumPrinter", \
        "Will we print 4 or 5?", \
        "Just because", \
        1, 0, 0, 1, 0, \
        GUID_NumberScenario, \
        2, \
        { \
            NUM_BRANCH_DETAIL_7, \
            NUM_BRANCH_DETAIL_VISTA \
        } \
    }

#define DIFF_WORD_SCENARIO \
    { \
        "YesNoPrinter", \
        "Will we say yes or no?", \
        "Just because", \
        1, 0, 0, 1, 0, \
        GUID_WordScenario, \
        2, \
        { \
            WORD_BRANCH_DETAIL_7, \
            WORD_BRANCH_DETAIL_VISTA \
        } \
    }

SWITCHBRANCH_SCENARIO_TABLE_ENTRY g_numEntry = DIFF_NUM_SCENARIO;
SWITCHBRANCH_SCENARIO_TABLE_ENTRY g_wordEntry = DIFF_WORD_SCENARIO;

enum ScenarioId
{
    NumScenario,
    WordScenario
};

SWITCHBRANCH_SCENARIO_TABLE_ENTRIES g_scenarios = {
    2,
    {
        &g_numEntry,
        &g_wordEntry
    }
};

SWITCHBRANCH_CACHED_MODULE_TABLE g_moduleTable = {
    0ULL,
    0,
    2,
    {NULL, NULL}
};

PVOID NTAPI ScenarioFilter(PVOID)
{
    return "MySampleScenarios";
}

const SWITCHBRANCH_SCENARIO_TABLE g_scenarioInfo = {
    'EsLk',
    0x01000000,
    &g_moduleTable,
    NULL,
    &g_scenarios,
    &ScenarioFilter
};

// This is how the branch functions are coded
// in the kernel32.dll/ddraw.dll etc
PVOID NTAPI NumBranchForVista(PVOID p)
{
    int* pFlag = (int*)p;
    *pFlag = 0;
    return p;
}

PVOID NTAPI NumBranchFor7(PVOID p)
{
    int* pFlag = (int*)p;
    *pFlag = 1;
    return p;
}

PVOID NTAPI WordBranchForVista(PVOID p)
{
    const char** ppWord = (const char**)p;
    *ppWord = "No";
    return p;
}

PVOID NTAPI WordBranchFor7(PVOID p)
{
    const char** ppWord = (const char**)p;
    *ppWord = "Yes";
    return p;
}

// If you compile this and use a manifest with only Vista as a supported OS
// or no supportedOS guids at all, it'll print the Vista values
// If you then add a Windows 7 supportedOS and run it again
// it'll print the 7 values
int __cdecl wmain(int argc, wchar_t** argv)
{
    int flag = -1;
    const char* pAnswer = NULL. pRet = NULL;
    pfnBranchFunc pBranchFunc = (pfnBranchFunc)SbSelectProcedure(0xABABABAB, 1, &g_scenarioInfo, NumScenario);
    pBranchFunc(&flag);
    printf("Thanks to the version manifesting, we're printing %d\n", 4 + flag);
    pRet = (const char*)SbExecuteProcedure(0, 1, &g_scenarioInfo, WordScenario, &pAnswer);
    printf("Thanks to the version manifesting, the answer to \"Do we like this OS?\" is %s\n", pAnswer);
    return 0;