├── .gitignore ├── LICENSE ├── beacon.h ├── examples ├── cs_beacon_info │ ├── build.bat │ ├── build.sh │ ├── cs_beacon_info.c │ └── cs_beacon_info.cna ├── cs_beacon_syscalls │ ├── build.bat │ ├── build.sh │ ├── cs_beacon_syscalls.cna │ ├── cs_beacon_syscalls_info.c │ └── cs_beacon_syscalls_test.c ├── cs_format_example │ ├── build.bat │ ├── build.sh │ ├── cs_format_example.c │ └── cs_format_example.cna ├── cs_key_value │ ├── build.bat │ ├── build.sh │ ├── cs_key_value.c │ └── cs_key_value.cna ├── cs_read_virtual_memory │ ├── build.bat │ ├── build.sh │ ├── cs_read_virtual_memory.c │ └── cs_read_virtual_memory.cna ├── demo │ ├── build.bat │ ├── build.sh │ ├── demo.c │ └── demo.cna ├── hello │ ├── build.bat │ ├── build.sh │ ├── hello.c │ └── hello.cna └── helloWorld │ ├── build.bat │ ├── build.sh │ └── hello.c ├── readme.md └── tests ├── bof_test_runner.cna ├── build.sh └── src ├── testBeaconDataIntegers.c ├── testBeaconDataLongLong.c ├── testBeaconDataMixDataTypes.c ├── testBeaconDataShorts.c ├── testBeaconDataStrings.c ├── testBeaconErrorD.c ├── testBeaconErrorDD.c ├── testBeaconErrorNA.c ├── testBeaconFormat.c ├── testBeaconOutput.c └── testBeaconPrintf.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object Files 2 | *.o 3 | 4 | # IntelliJ files 5 | *.iml 6 | .idea 7 | 8 | # MacOS 9 | 10 | # General 11 | .DS_Store 12 | .AppleDouble 13 | .LSOverride 14 | 15 | # Icon must end with two \r 16 | Icon 17 | 18 | 19 | # Thumbnails 20 | ._* 21 | 22 | # Files that might appear in the root of a volume 23 | .DocumentRevisions-V100 24 | .fseventsd 25 | .Spotlight-V100 26 | .TemporaryItems 27 | .Trashes 28 | .VolumeIcon.icns 29 | .com.apple.timemachine.donotpresent 30 | 31 | # Directories potentially created on remote AFP share 32 | .AppleDB 33 | .AppleDesktop 34 | Network Trash Folder 35 | Temporary Items 36 | .apdisk 37 | 38 | # Linux 39 | 40 | *~ 41 | 42 | # temporary files which can be created if a process still has a handle open of a deleted file 43 | .fuse_hidden* 44 | 45 | # KDE directory preferences 46 | .directory 47 | 48 | # Linux trash folder which might appear on any partition or disk 49 | .Trash-* 50 | 51 | # .nfs files are created when an open file is removed but is still being accessed 52 | .nfs* 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Additional BOF resources are available here: 8 | * - https://github.com/Cobalt-Strike/bof_template 9 | * 10 | * Cobalt Strike 4.x 11 | * ChangeLog: 12 | * 1/25/2022: updated for 4.5 13 | * 7/18/2023: Added BeaconInformation API for 4.9 14 | * 7/31/2023: Added Key/Value store APIs for 4.9 15 | * BeaconAddValue, BeaconGetValue, and BeaconRemoveValue 16 | * 8/31/2023: Added Data store APIs for 4.9 17 | * BeaconDataStoreGetItem, BeaconDataStoreProtectItem, 18 | * BeaconDataStoreUnprotectItem, and BeaconDataStoreMaxEntries 19 | * 9/01/2023: Added BeaconGetCustomUserData API for 4.9 20 | * 3/21/2024: Updated BeaconInformation API for 4.10 to return a BOOL 21 | * Updated the BEACON_INFO data structure to add new parameters 22 | * 4/19/2024: Added BeaconGetSyscallInformation API for 4.10 23 | * 4/25/2024: Added APIs to call Beacon's system call implementation 24 | * 12/18/2024: Updated BeaconGetSyscallInformation API for 4.11 (Breaking changes) 25 | * 2/13/2025: Updated SYSCALL_API structure with more ntAPIs 26 | */ 27 | #ifndef _BEACON_H_ 28 | #define _BEACON_H_ 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif // __cplusplus 34 | 35 | /* data API */ 36 | typedef struct { 37 | char * original; /* the original buffer [so we can free it] */ 38 | char * buffer; /* current pointer into our buffer */ 39 | int length; /* remaining length of data */ 40 | int size; /* total size of this buffer */ 41 | } datap; 42 | 43 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 44 | DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size); 45 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 46 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 47 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 48 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 49 | 50 | /* format API */ 51 | typedef struct { 52 | char * original; /* the original buffer [so we can free it] */ 53 | char * buffer; /* current pointer into our buffer */ 54 | int length; /* remaining length of data */ 55 | int size; /* total size of this buffer */ 56 | } formatp; 57 | 58 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 59 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 60 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, const char * text, int len); 61 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, const char * fmt, ...); 62 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 63 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 64 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 65 | 66 | /* Output Functions */ 67 | #define CALLBACK_OUTPUT 0x0 68 | #define CALLBACK_OUTPUT_OEM 0x1e 69 | #define CALLBACK_OUTPUT_UTF8 0x20 70 | #define CALLBACK_ERROR 0x0d 71 | #define CALLBACK_CUSTOM 0x1000 72 | #define CALLBACK_CUSTOM_LAST 0x13ff 73 | 74 | 75 | DECLSPEC_IMPORT void BeaconOutput(int type, const char * data, int len); 76 | DECLSPEC_IMPORT void BeaconPrintf(int type, const char * fmt, ...); 77 | 78 | 79 | /* Token Functions */ 80 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 81 | DECLSPEC_IMPORT void BeaconRevertToken(); 82 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 83 | 84 | /* Spawn+Inject Functions */ 85 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 86 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 87 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 88 | DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo); 89 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 90 | 91 | /* Utility Functions */ 92 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 93 | 94 | /* Beacon Information */ 95 | /* 96 | * ptr - pointer to the base address of the allocated memory. 97 | * size - the number of bytes allocated for the ptr. 98 | */ 99 | typedef struct { 100 | char * ptr; 101 | size_t size; 102 | } HEAP_RECORD; 103 | #define MASK_SIZE 13 104 | 105 | /* Information the user can set in the USER_DATA via a UDRL */ 106 | typedef enum { 107 | PURPOSE_EMPTY, 108 | PURPOSE_GENERIC_BUFFER, 109 | PURPOSE_BEACON_MEMORY, 110 | PURPOSE_SLEEPMASK_MEMORY, 111 | PURPOSE_BOF_MEMORY, 112 | PURPOSE_USER_DEFINED_MEMORY = 1000 113 | } ALLOCATED_MEMORY_PURPOSE; 114 | 115 | typedef enum { 116 | LABEL_EMPTY, 117 | LABEL_BUFFER, 118 | LABEL_PEHEADER, 119 | LABEL_TEXT, 120 | LABEL_RDATA, 121 | LABEL_DATA, 122 | LABEL_PDATA, 123 | LABEL_RELOC, 124 | LABEL_USER_DEFINED = 1000 125 | } ALLOCATED_MEMORY_LABEL; 126 | 127 | typedef enum { 128 | METHOD_UNKNOWN, 129 | METHOD_VIRTUALALLOC, 130 | METHOD_HEAPALLOC, 131 | METHOD_MODULESTOMP, 132 | METHOD_NTMAPVIEW, 133 | METHOD_USER_DEFINED = 1000, 134 | } ALLOCATED_MEMORY_ALLOCATION_METHOD; 135 | 136 | /** 137 | * This structure allows the user to provide additional information 138 | * about the allocated heap for cleanup. It is mandatory to provide 139 | * the HeapHandle but the DestroyHeap Boolean can be used to indicate 140 | * whether the clean up code should destroy the heap or simply free the pages. 141 | * This is useful in situations where a loader allocates memory in the 142 | * processes current heap. 143 | */ 144 | typedef struct _HEAPALLOC_INFO { 145 | PVOID HeapHandle; 146 | BOOL DestroyHeap; 147 | } HEAPALLOC_INFO, *PHEAPALLOC_INFO; 148 | 149 | typedef struct _MODULESTOMP_INFO { 150 | HMODULE ModuleHandle; 151 | } MODULESTOMP_INFO, *PMODULESTOMP_INFO; 152 | 153 | typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION { 154 | HEAPALLOC_INFO HeapAllocInfo; 155 | MODULESTOMP_INFO ModuleStompInfo; 156 | PVOID Custom; 157 | } ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION; 158 | 159 | typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION { 160 | BOOL Cleanup; 161 | ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod; 162 | ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation; 163 | } ALLOCATED_MEMORY_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_CLEANUP_INFORMATION; 164 | 165 | typedef struct _ALLOCATED_MEMORY_SECTION { 166 | ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development 167 | PVOID BaseAddress; // Pointer to virtual address of section 168 | SIZE_T VirtualSize; // Virtual size of the section 169 | DWORD CurrentProtect; // Current memory protection of the section 170 | DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking) 171 | BOOL MaskSection; // A boolean to indicate whether the section should be masked 172 | } ALLOCATED_MEMORY_SECTION, *PALLOCATED_MEMORY_SECTION; 173 | 174 | typedef struct _ALLOCATED_MEMORY_REGION { 175 | ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory 176 | PVOID AllocationBase; // The base address of the allocated memory block 177 | SIZE_T RegionSize; // The size of the allocated memory block 178 | DWORD Type; // The type of memory allocated 179 | ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures 180 | ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation 181 | } ALLOCATED_MEMORY_REGION, *PALLOCATED_MEMORY_REGION; 182 | 183 | typedef struct { 184 | ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6]; 185 | } ALLOCATED_MEMORY, *PALLOCATED_MEMORY; 186 | 187 | /* 188 | * version - The version of the beacon dll was added for release 4.10 189 | * version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch 190 | * e.g. 0x040900 -> CS 4.9 191 | * 0x041000 -> CS 4.10 192 | * 193 | * sleep_mask_ptr - pointer to the sleep mask base address 194 | * sleep_mask_text_size - the sleep mask text section size 195 | * sleep_mask_total_size - the sleep mask total memory size 196 | * 197 | * beacon_ptr - pointer to beacon's base address 198 | * The stage.obfuscate flag affects this value when using CS default loader. 199 | * true: beacon_ptr = allocated_buffer - 0x1000 (Not a valid address) 200 | * false: beacon_ptr = allocated_buffer (A valid address) 201 | * For a UDRL the beacon_ptr will be set to the 1st argument to DllMain 202 | * when the 2nd argument is set to DLL_PROCESS_ATTACH. 203 | * heap_records - list of memory addresses on the heap beacon wants to mask. 204 | * The list is terminated by the HEAP_RECORD.ptr set to NULL. 205 | * mask - the mask that beacon randomly generated to apply 206 | * 207 | * Added in version 4.10 208 | * allocatedMemory - An ALLOCATED_MEMORY structure that can be set in the USER_DATA 209 | * via a UDRL. 210 | */ 211 | typedef struct { 212 | unsigned int version; 213 | char * sleep_mask_ptr; 214 | DWORD sleep_mask_text_size; 215 | DWORD sleep_mask_total_size; 216 | 217 | char * beacon_ptr; 218 | HEAP_RECORD * heap_records; 219 | char mask[MASK_SIZE]; 220 | 221 | ALLOCATED_MEMORY allocatedMemory; 222 | } BEACON_INFO, *PBEACON_INFO; 223 | 224 | DECLSPEC_IMPORT BOOL BeaconInformation(PBEACON_INFO info); 225 | 226 | /* Key/Value store functions 227 | * These functions are used to associate a key to a memory address and save 228 | * that information into beacon. These memory addresses can then be 229 | * retrieved in a subsequent execution of a BOF. 230 | * 231 | * key - the key will be converted to a hash which is used to locate the 232 | * memory address. 233 | * 234 | * ptr - a memory address to save. 235 | * 236 | * Considerations: 237 | * - The contents at the memory address is not masked by beacon. 238 | * - The contents at the memory address is not released by beacon. 239 | * 240 | */ 241 | DECLSPEC_IMPORT BOOL BeaconAddValue(const char * key, void * ptr); 242 | DECLSPEC_IMPORT void * BeaconGetValue(const char * key); 243 | DECLSPEC_IMPORT BOOL BeaconRemoveValue(const char * key); 244 | 245 | /* Beacon Data Store functions 246 | * These functions are used to access items in Beacon's Data Store. 247 | * BeaconDataStoreGetItem returns NULL if the index does not exist. 248 | * 249 | * The contents are masked by default, and BOFs must unprotect the entry 250 | * before accessing the data buffer. BOFs must also protect the entry 251 | * after the data is not used anymore. 252 | * 253 | */ 254 | 255 | #define DATA_STORE_TYPE_EMPTY 0 256 | #define DATA_STORE_TYPE_GENERAL_FILE 1 257 | 258 | typedef struct { 259 | int type; 260 | DWORD64 hash; 261 | BOOL masked; 262 | char* buffer; 263 | size_t length; 264 | } DATA_STORE_OBJECT, *PDATA_STORE_OBJECT; 265 | 266 | DECLSPEC_IMPORT PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index); 267 | DECLSPEC_IMPORT void BeaconDataStoreProtectItem(size_t index); 268 | DECLSPEC_IMPORT void BeaconDataStoreUnprotectItem(size_t index); 269 | DECLSPEC_IMPORT size_t BeaconDataStoreMaxEntries(); 270 | 271 | /* Beacon User Data functions */ 272 | DECLSPEC_IMPORT char * BeaconGetCustomUserData(); 273 | 274 | /* Beacon System call */ 275 | /* Syscalls API */ 276 | typedef struct 277 | { 278 | PVOID fnAddr; 279 | PVOID jmpAddr; 280 | DWORD sysnum; 281 | } SYSCALL_API_ENTRY, *PSYSCALL_API_ENTRY; 282 | 283 | typedef struct 284 | { 285 | SYSCALL_API_ENTRY ntAllocateVirtualMemory; 286 | SYSCALL_API_ENTRY ntProtectVirtualMemory; 287 | SYSCALL_API_ENTRY ntFreeVirtualMemory; 288 | SYSCALL_API_ENTRY ntGetContextThread; 289 | SYSCALL_API_ENTRY ntSetContextThread; 290 | SYSCALL_API_ENTRY ntResumeThread; 291 | SYSCALL_API_ENTRY ntCreateThreadEx; 292 | SYSCALL_API_ENTRY ntOpenProcess; 293 | SYSCALL_API_ENTRY ntOpenThread; 294 | SYSCALL_API_ENTRY ntClose; 295 | SYSCALL_API_ENTRY ntCreateSection; 296 | SYSCALL_API_ENTRY ntMapViewOfSection; 297 | SYSCALL_API_ENTRY ntUnmapViewOfSection; 298 | SYSCALL_API_ENTRY ntQueryVirtualMemory; 299 | SYSCALL_API_ENTRY ntDuplicateObject; 300 | SYSCALL_API_ENTRY ntReadVirtualMemory; 301 | SYSCALL_API_ENTRY ntWriteVirtualMemory; 302 | SYSCALL_API_ENTRY ntReadFile; 303 | SYSCALL_API_ENTRY ntWriteFile; 304 | SYSCALL_API_ENTRY ntCreateFile; 305 | SYSCALL_API_ENTRY ntQueueApcThread; 306 | SYSCALL_API_ENTRY ntCreateProcess; 307 | SYSCALL_API_ENTRY ntOpenProcessToken; 308 | SYSCALL_API_ENTRY ntTestAlert; 309 | SYSCALL_API_ENTRY ntSuspendProcess; 310 | SYSCALL_API_ENTRY ntResumeProcess; 311 | SYSCALL_API_ENTRY ntQuerySystemInformation; 312 | SYSCALL_API_ENTRY ntQueryDirectoryFile; 313 | SYSCALL_API_ENTRY ntSetInformationProcess; 314 | SYSCALL_API_ENTRY ntSetInformationThread; 315 | SYSCALL_API_ENTRY ntQueryInformationProcess; 316 | SYSCALL_API_ENTRY ntQueryInformationThread; 317 | SYSCALL_API_ENTRY ntOpenSection; 318 | SYSCALL_API_ENTRY ntAdjustPrivilegesToken; 319 | SYSCALL_API_ENTRY ntDeviceIoControlFile; 320 | SYSCALL_API_ENTRY ntWaitForMultipleObjects; 321 | } SYSCALL_API, *PSYSCALL_API; 322 | 323 | /* Additional Run Time Library (RTL) addresses used to support system calls. 324 | * If they are not set then system calls that require them will fall back 325 | * to the Standard Windows API. 326 | * 327 | * Required to support the following system calls: 328 | * ntCreateFile 329 | */ 330 | typedef struct 331 | { 332 | PVOID rtlDosPathNameToNtPathNameUWithStatusAddr; 333 | PVOID rtlFreeHeapAddr; 334 | PVOID rtlGetProcessHeapAddr; 335 | } RTL_API, *PRTL_API; 336 | 337 | /* Updated in version 4.11 to use the entire structure instead of pointers to the structure. 338 | * This allows for retrieving a copy of the information which would be under the BOF's 339 | * control instead of a reference pointer which may be obfuscated when beacon is sleeping. 340 | */ 341 | typedef struct 342 | { 343 | SYSCALL_API syscalls; 344 | RTL_API rtls; 345 | } BEACON_SYSCALLS, *PBEACON_SYSCALLS; 346 | 347 | /* Updated in version 4.11 to include the size of the info pointer, which equals sizeof(BEACON_SYSCALLS) */ 348 | DECLSPEC_IMPORT BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, SIZE_T infoSize, BOOL resolveIfNotInitialized); 349 | 350 | /* Beacon System call functions which will use the current system call method */ 351 | DECLSPEC_IMPORT LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 352 | DECLSPEC_IMPORT LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 353 | DECLSPEC_IMPORT BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); 354 | DECLSPEC_IMPORT BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); 355 | DECLSPEC_IMPORT BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); 356 | DECLSPEC_IMPORT BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext); 357 | DECLSPEC_IMPORT BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext); 358 | DECLSPEC_IMPORT DWORD BeaconResumeThread(HANDLE threadHandle); 359 | DECLSPEC_IMPORT HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId); 360 | DECLSPEC_IMPORT HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId); 361 | DECLSPEC_IMPORT BOOL BeaconCloseHandle(HANDLE object); 362 | DECLSPEC_IMPORT BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress); 363 | DECLSPEC_IMPORT SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length); 364 | DECLSPEC_IMPORT BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); 365 | DECLSPEC_IMPORT BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead); 366 | DECLSPEC_IMPORT BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten); 367 | 368 | /* Beacon Gate APIs */ 369 | DECLSPEC_IMPORT VOID BeaconDisableBeaconGate(); 370 | DECLSPEC_IMPORT VOID BeaconEnableBeaconGate(); 371 | 372 | DECLSPEC_IMPORT VOID BeaconDisableBeaconGateMasking(); 373 | DECLSPEC_IMPORT VOID BeaconEnableBeaconGateMasking(); 374 | 375 | /* Beacon User Data 376 | * 377 | * version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch 378 | * e.g. 0x040900 -> CS 4.9 379 | * 0x041000 -> CS 4.10 380 | */ 381 | 382 | #define DLL_BEACON_USER_DATA 0x0d 383 | #define BEACON_USER_DATA_CUSTOM_SIZE 32 384 | typedef struct 385 | { 386 | unsigned int version; 387 | PSYSCALL_API syscalls; 388 | char custom[BEACON_USER_DATA_CUSTOM_SIZE]; 389 | PRTL_API rtls; 390 | PALLOCATED_MEMORY allocatedMemory; 391 | } USER_DATA, * PUSER_DATA; 392 | 393 | #ifdef __cplusplus 394 | } 395 | #endif // __cplusplus 396 | #endif // _BEACON_H_ 397 | -------------------------------------------------------------------------------- /examples/cs_beacon_info/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- cs_beacon_info.c /Focs_beacon_info.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/cs_beacon_info/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c cs_beacon_info.c -o cs_beacon_info.x86.o 4 | x86_64-w64-mingw32-gcc -c cs_beacon_info.c -o cs_beacon_info.x64.o 5 | -------------------------------------------------------------------------------- /examples/cs_beacon_info/cs_beacon_info.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../beacon.h" 3 | 4 | 5 | void dump_mask(formatp * buffer, BEACON_INFO * info) { 6 | char hex_array[] = "0123456789abcdef"; 7 | char mask_hex[MASK_SIZE * 3 + 1] = { 0 }; 8 | 9 | for (int i = 0, j = 0; i < MASK_SIZE; ++i, ++j) { 10 | int v = info->mask[i] & 0xFF; 11 | mask_hex[j * 3] = hex_array[(unsigned int) (v >> 4)]; 12 | mask_hex[j * 3 + 1] = hex_array[v & 0x0F]; 13 | mask_hex[j * 3 + 2] = ' '; 14 | } 15 | BeaconFormatPrintf(buffer, "\n\tMask: %s\n", mask_hex); 16 | } 17 | 18 | void dump_heap_records(formatp * buffer, BEACON_INFO * info) { 19 | 20 | if (info->heap_records == NULL) { 21 | BeaconFormatPrintf(buffer, "\n\tNo heap records\n"); 22 | return; 23 | } 24 | 25 | /* walk the heap records */ 26 | BeaconFormatPrintf(buffer, "\n\tHeap records:\n"); 27 | for (int i = 0; info->heap_records[i].ptr != NULL; ++i) { 28 | BeaconFormatPrintf(buffer, "\t\tRecord[%2d]: Address: %p Size %8lu\n", 29 | i, info->heap_records[i].ptr, info->heap_records[i].size); 30 | } 31 | } 32 | 33 | static const char * getPurpose(ALLOCATED_MEMORY_PURPOSE purpose) { 34 | if (purpose == PURPOSE_EMPTY) 35 | return "PURPOSE_EMPTY"; 36 | if (purpose == PURPOSE_GENERIC_BUFFER) 37 | return "PURPOSE_GENERIC_BUFFER"; 38 | if (purpose == PURPOSE_BEACON_MEMORY) 39 | return "PURPOSE_BEACON_MEMORY"; 40 | if (purpose == PURPOSE_SLEEPMASK_MEMORY) 41 | return "PURPOSE_SLEEPMASK_MEMORY"; 42 | if (purpose == PURPOSE_BOF_MEMORY) 43 | return "PURPOSE_BOF_MEMORY"; 44 | if (purpose == PURPOSE_USER_DEFINED_MEMORY) 45 | return "PURPOSE_USER_DEFINED_MEMORY"; 46 | 47 | return "PURPOSE_UNKNOWN"; 48 | } 49 | 50 | static const char * getLabel(ALLOCATED_MEMORY_LABEL label) { 51 | if (label == LABEL_EMPTY) 52 | return "LABEL_EMPTY"; 53 | if (label == LABEL_BUFFER) 54 | return "LABEL_BUFFER"; 55 | if (label == LABEL_PEHEADER) 56 | return "LABEL_PEHEADER"; 57 | if (label == LABEL_TEXT) 58 | return "LABEL_TEXT"; 59 | if (label == LABEL_RDATA) 60 | return "LABEL_RDATA"; 61 | if (label == LABEL_DATA) 62 | return "LABEL_DATA"; 63 | if (label == LABEL_PDATA) 64 | return "LABEL_PDATA"; 65 | if (label == LABEL_RELOC) 66 | return "LABEL_RELOC"; 67 | if (label == LABEL_USER_DEFINED) 68 | return "LABEL_USER_DEFINED"; 69 | 70 | return "LABEL_UNKNOWN"; 71 | } 72 | 73 | static void dump_allocated_memory_section(formatp *buffer, PALLOCATED_MEMORY_SECTION memorySection) { 74 | BeaconFormatPrintf(buffer, "\t\t\tLabel: %s\n", getLabel(memorySection->Label)); 75 | BeaconFormatPrintf(buffer, "\t\t\tBaseAddress: %p\n", memorySection->BaseAddress); 76 | BeaconFormatPrintf(buffer, "\t\t\tVirtualSize: 0x%x (%lu)\n", memorySection->VirtualSize, memorySection->VirtualSize); 77 | BeaconFormatPrintf(buffer, "\t\t\tCurrenProtection: 0x%x\n", memorySection->CurrentProtect); 78 | BeaconFormatPrintf(buffer, "\t\t\tPreviousProtect: 0x%x\n", memorySection->PreviousProtect); 79 | BeaconFormatPrintf(buffer, "\t\t\tMaskSection: %s\n", memorySection->MaskSection ? "TRUE" : "FALSE"); 80 | } 81 | 82 | static void dump_allocated_memory_cleanup_information(formatp *buffer, PALLOCATED_MEMORY_CLEANUP_INFORMATION cleanupInformation) { 83 | BeaconFormatPrintf(buffer, "\t\tCleanup Information:\n"); 84 | BeaconFormatPrintf(buffer, "\t\t\tCleanup: %s\n", cleanupInformation->Cleanup ? "TRUE" : "FALSE"); 85 | 86 | if (cleanupInformation->AllocationMethod == METHOD_HEAPALLOC) { 87 | BeaconFormatPrintf(buffer, "\t\t\tAllocationMethod: METHOD_HEAPALLOC\n"); 88 | BeaconFormatPrintf(buffer, "\t\t\tAdditionalCleanupInformation: HeapHandle: %p\n", cleanupInformation->AdditionalCleanupInformation.HeapAllocInfo.HeapHandle); 89 | BeaconFormatPrintf(buffer, "\t\t\tAdditionalCleanupInformation: DestroyHeap: %s\n", cleanupInformation->AdditionalCleanupInformation.HeapAllocInfo.DestroyHeap? "TRUE" : "FALSE"); 90 | } 91 | else if (cleanupInformation->AllocationMethod == METHOD_MODULESTOMP) { 92 | BeaconFormatPrintf(buffer, "\t\t\tAllocationMethod: METHOD_MODULESTOMP\n"); 93 | BeaconFormatPrintf(buffer, "\t\t\tAdditionalCleanupInformation: ModuleHandle: %p\n", cleanupInformation->AdditionalCleanupInformation.ModuleStompInfo.ModuleHandle); 94 | } 95 | else { 96 | if (cleanupInformation->AllocationMethod == METHOD_VIRTUALALLOC) { 97 | BeaconFormatPrintf(buffer, "\t\t\tAllocationMethod: METHOD_VIRTUALALLOC\n"); 98 | } 99 | else if (cleanupInformation->AllocationMethod == METHOD_NTMAPVIEW) { 100 | BeaconFormatPrintf(buffer, "\t\t\tAllocationMethod: METHOD_NTMAPVIEW\n"); 101 | } 102 | else if (cleanupInformation->AllocationMethod == METHOD_UNKNOWN) { 103 | BeaconFormatPrintf(buffer, "\t\t\tAllocationMethod: METHOD_UNKNOWN\n"); 104 | } 105 | else { 106 | BeaconFormatPrintf(buffer, "\t\t\tAllocationMethod: METHOD_USER_DEFINED (%d)\n", cleanupInformation->AllocationMethod); 107 | } 108 | BeaconFormatPrintf(buffer, "\t\t\tAdditionalCleanupInformation: NONE\n"); 109 | } 110 | } 111 | 112 | static void dump_allocated_memory_region(formatp * buffer, PALLOCATED_MEMORY_REGION memoryRegion) { 113 | int i = 0; 114 | 115 | BeaconFormatPrintf(buffer, "\t\tPurpose: %s\n", getPurpose(memoryRegion->Purpose)); 116 | BeaconFormatPrintf(buffer, "\t\tBaseAddress: %p\n", memoryRegion->AllocationBase); 117 | BeaconFormatPrintf(buffer, "\t\tRegionSize: 0x%x (%lu)\n", memoryRegion->RegionSize, memoryRegion->RegionSize); 118 | BeaconFormatPrintf(buffer, "\t\tType: 0x%x\n", memoryRegion->Type); 119 | 120 | /* loop through the Sections */ 121 | for (i = 0; i < sizeof(memoryRegion->Sections) / sizeof(ALLOCATED_MEMORY_SECTION); ++i) { 122 | if (memoryRegion->Sections[i].Label == LABEL_EMPTY) { 123 | continue; 124 | } 125 | BeaconFormatPrintf(buffer, "\t\tSection[%d]\n", i); 126 | dump_allocated_memory_section(buffer, &memoryRegion->Sections[i]); 127 | } 128 | 129 | dump_allocated_memory_cleanup_information(buffer, &memoryRegion->CleanupInformation); 130 | } 131 | 132 | void dump_allocated_memory(formatp * buffer, PBEACON_INFO info) { 133 | int counted_entries = 0; 134 | int total_entries = sizeof(info->allocatedMemory.AllocatedMemoryRegions) / sizeof(ALLOCATED_MEMORY_REGION); 135 | 136 | BeaconFormatPrintf(buffer, "\nAllocated memory:\n"); 137 | for (int i = 0; i < total_entries; ++i) { 138 | PALLOCATED_MEMORY_REGION memoryRegion = &(info->allocatedMemory.AllocatedMemoryRegions[i]); 139 | if (memoryRegion->Purpose != PURPOSE_EMPTY) { 140 | ++counted_entries; 141 | BeaconFormatPrintf(buffer, "\tAllocated memory region[%d]:\n", i); 142 | dump_allocated_memory_region(buffer, memoryRegion); 143 | } 144 | } 145 | BeaconFormatPrintf(buffer, "\nAllocated memory structure set %d entries out of %d available entries\n", 146 | counted_entries, total_entries); 147 | } 148 | 149 | /* entry point */ 150 | void go(char * args, int alen) { 151 | formatp buffer; 152 | int size = 0; 153 | BEACON_INFO info = { 0 }; 154 | char *userData = NULL; 155 | 156 | /* Call beacon api to get the information */ 157 | info.version = 0x041000; 158 | if (!BeaconInformation(&info)) { 159 | BeaconPrintf(CALLBACK_ERROR, "BeaconInformation failed: unhandled version: 0x%x\n", info.version); 160 | return; 161 | } 162 | 163 | /* Allocate space for formatted output buffer */ 164 | BeaconFormatAlloc(&buffer, 16 * 1024); 165 | 166 | /* Generate the output */ 167 | BeaconFormatPrintf(&buffer, "Beacon Information:\n"); 168 | BeaconFormatPrintf(&buffer, "\tBase address: %p\n", info.beacon_ptr); 169 | dump_allocated_memory(&buffer, &info); 170 | dump_heap_records(&buffer, &info); 171 | dump_mask(&buffer, &info); 172 | BeaconFormatPrintf(&buffer, "\nSleep Mask Information:\n"); 173 | BeaconFormatPrintf(&buffer, "\tBase address: %p\n", info.sleep_mask_ptr); 174 | BeaconFormatPrintf(&buffer, "\tText size : %lu\n", info.sleep_mask_text_size); 175 | BeaconFormatPrintf(&buffer, "\tTotal size : %lu\n", info.sleep_mask_total_size); 176 | 177 | /* Send the buffer of information with */ 178 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&buffer, &size)); 179 | 180 | /* Cleanup */ 181 | BeaconFormatFree(&buffer); 182 | } 183 | -------------------------------------------------------------------------------- /examples/cs_beacon_info/cs_beacon_info.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "cs_beacon_info", 3 | "Used to display the information returned from the BeaconInformation API", 4 | 5 | "Used to display the information returned from the BeaconInformation API\n\n" . 6 | 7 | "Usage:\n" . 8 | " cs_beacon_info\n\n" . 9 | 10 | "Arguments:\n" . 11 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 12 | 13 | "Examples:\n" . 14 | " cs_beacon_info\n\n" 15 | ); 16 | 17 | # Arguments 18 | # $1 - beacon id 19 | alias cs_beacon_info { 20 | local('$bid $barch $handle $data'); 21 | 22 | # Assign parameters user friendly names 23 | ($bid) = @_; 24 | 25 | # figure out the arch of this session 26 | $barch = barch($bid); 27 | 28 | # read in the right BOF file 29 | $handle = openf(script_resource("cs_beacon_info. $+ $barch $+ .o")); 30 | $data = readb($handle, -1); 31 | closef($handle); 32 | 33 | # announce what we're doing 34 | btask($bid, "Running cs_beacon_info BOF"); 35 | 36 | # execute it. 37 | beacon_inline_execute($bid, $data, "go", $null); 38 | } 39 | -------------------------------------------------------------------------------- /examples/cs_beacon_syscalls/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- cs_beacon_syscalls_info.c /Focs_beacon_syscalls_info.%PLAT%.o 7 | cl.exe /D %VERSION% /c /GS- cs_beacon_syscalls_test.c /Focs_beacon_syscalls_test.%PLAT%.o 8 | -------------------------------------------------------------------------------- /examples/cs_beacon_syscalls/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c cs_beacon_syscalls_info.c -o cs_beacon_syscalls_info.x86.o 4 | x86_64-w64-mingw32-gcc -c cs_beacon_syscalls_info.c -o cs_beacon_syscalls_info.x64.o 5 | 6 | i686-w64-mingw32-gcc -c cs_beacon_syscalls_test.c -o cs_beacon_syscalls_test.x86.o 7 | x86_64-w64-mingw32-gcc -c cs_beacon_syscalls_test.c -o cs_beacon_syscalls_test.x64.o 8 | -------------------------------------------------------------------------------- /examples/cs_beacon_syscalls/cs_beacon_syscalls.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "cs_beacon_syscalls_info", 3 | "Used to display the information returned from the BeaconGetSyscallInformation API", 4 | 5 | "Used to display the information returned from the BeaconGetSyscallInformation API\n\n" . 6 | 7 | "Usage:\n" . 8 | " cs_beacon_syscalls_info\n\n" . 9 | 10 | "Arguments:\n" . 11 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 12 | 13 | "Examples:\n" . 14 | " cs_beacon_syscalls_info\n\n" 15 | ); 16 | 17 | # Arguments 18 | # $1 - beacon id 19 | alias cs_beacon_syscalls_info { 20 | local('$bid $barch $handle $data'); 21 | 22 | # Assign parameters user friendly names 23 | ($bid) = @_; 24 | 25 | # figure out the arch of this session 26 | $barch = barch($bid); 27 | 28 | # read in the right BOF file 29 | $handle = openf(script_resource("cs_beacon_syscalls_info. $+ $barch $+ .o")); 30 | $data = readb($handle, -1); 31 | closef($handle); 32 | 33 | # announce what we're doing 34 | btask($bid, "Running cs_beacon_syscalls_info BOF"); 35 | 36 | # execute it. 37 | beacon_inline_execute($bid, $data, "go", $null); 38 | } 39 | 40 | beacon_command_register( 41 | "cs_beacon_syscalls_test", 42 | "Used to test and show examples of using beacon's system calls", 43 | 44 | "Used to test and show examples of using beacon's system calls\n\n" . 45 | 46 | "Usage:\n" . 47 | " cs_beacon_syscalls_test\n\n" . 48 | 49 | "Arguments:\n" . 50 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 51 | 52 | "Examples:\n" . 53 | " cs_beacon_syscalls_test\n\n" 54 | ); 55 | 56 | # Arguments 57 | # $1 - beacon id 58 | alias cs_beacon_syscalls_test { 59 | local('$bid $barch $handle $data'); 60 | 61 | # Assign parameters user friendly names 62 | ($bid) = @_; 63 | 64 | # figure out the arch of this session 65 | $barch = barch($bid); 66 | 67 | # read in the right BOF file 68 | $handle = openf(script_resource("cs_beacon_syscalls_test. $+ $barch $+ .o")); 69 | $data = readb($handle, -1); 70 | closef($handle); 71 | 72 | # announce what we're doing 73 | btask($bid, "Running cs_beacon_syscalls_test BOF"); 74 | 75 | # execute it. 76 | beacon_inline_execute($bid, $data, "go", $null); 77 | } 78 | -------------------------------------------------------------------------------- /examples/cs_beacon_syscalls/cs_beacon_syscalls_info.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../beacon.h" 3 | 4 | void dump_api_entry(formatp * buffer, char * name, PSYSCALL_API_ENTRY entry) { 5 | BeaconFormatPrintf(buffer, " %41s: fnAddr: %p jmpAddr: %p sysnum: %lu\n", 6 | name, 7 | entry->fnAddr, 8 | entry->jmpAddr, 9 | entry->sysnum); 10 | } 11 | 12 | void dump_rtl_entry(formatp * buffer, char * name, PVOID entry) { 13 | BeaconFormatPrintf(buffer, " %41s: fnAddr: %p\n", name, entry); 14 | } 15 | 16 | void dump_syscalls(formatp * buffer, PBEACON_SYSCALLS info) { 17 | if (info == NULL) { 18 | BeaconFormatPrintf(buffer, "Failed to get the beacon system call user data\n"); 19 | return; 20 | } 21 | 22 | BeaconFormatPrintf(buffer, "System Calls:\n"); 23 | dump_api_entry(buffer, "ntAllocateVirtualMemory", &info->syscalls.ntAllocateVirtualMemory); 24 | dump_api_entry(buffer, "ntProtectVirtualMemory", &info->syscalls.ntProtectVirtualMemory); 25 | dump_api_entry(buffer, "ntFreeVirtualMemory", &info->syscalls.ntFreeVirtualMemory); 26 | dump_api_entry(buffer, "ntGetContextThread", &info->syscalls.ntGetContextThread); 27 | dump_api_entry(buffer, "ntSetContextThread", &info->syscalls.ntSetContextThread); 28 | dump_api_entry(buffer, "ntResumeThread", &info->syscalls.ntResumeThread); 29 | dump_api_entry(buffer, "ntCreateThreadEx", &info->syscalls.ntCreateThreadEx); 30 | dump_api_entry(buffer, "ntOpenProcess", &info->syscalls.ntOpenProcess); 31 | dump_api_entry(buffer, "ntOpenThread", &info->syscalls.ntOpenThread); 32 | dump_api_entry(buffer, "ntClose", &info->syscalls.ntClose); 33 | dump_api_entry(buffer, "ntCreateSection", &info->syscalls.ntCreateSection); 34 | dump_api_entry(buffer, "ntMapViewOfSection", &info->syscalls.ntMapViewOfSection); 35 | dump_api_entry(buffer, "ntUnmapViewOfSection", &info->syscalls.ntUnmapViewOfSection); 36 | dump_api_entry(buffer, "ntQueryVirtualMemory", &info->syscalls.ntQueryVirtualMemory); 37 | dump_api_entry(buffer, "ntDuplicateObject", &info->syscalls.ntDuplicateObject); 38 | dump_api_entry(buffer, "ntReadVirtualMemory", &info->syscalls.ntReadVirtualMemory); 39 | dump_api_entry(buffer, "ntWriteVirtualMemory", &info->syscalls.ntWriteVirtualMemory); 40 | dump_api_entry(buffer, "ntReadFile", &info->syscalls.ntReadFile); 41 | dump_api_entry(buffer, "ntWriteFile", &info->syscalls.ntWriteFile); 42 | dump_api_entry(buffer, "ntCreateFile", &info->syscalls.ntCreateFile); 43 | dump_api_entry(buffer, "ntQueueApcThread", &info->syscalls.ntQueueApcThread); 44 | dump_api_entry(buffer, "ntCreateProcess", &info->syscalls.ntCreateProcess); 45 | dump_api_entry(buffer, "ntOpenProcessToken", &info->syscalls.ntOpenProcessToken); 46 | dump_api_entry(buffer, "ntTestAlert", &info->syscalls.ntTestAlert); 47 | dump_api_entry(buffer, "ntSuspendProcess", &info->syscalls.ntSuspendProcess); 48 | dump_api_entry(buffer, "ntResumeProcess", &info->syscalls.ntResumeProcess); 49 | dump_api_entry(buffer, "ntQuerySystemInformation", &info->syscalls.ntQuerySystemInformation); 50 | dump_api_entry(buffer, "ntQueryDirectoryFile", &info->syscalls.ntQueryDirectoryFile); 51 | dump_api_entry(buffer, "ntSetInformationProcess", &info->syscalls.ntSetInformationProcess); 52 | dump_api_entry(buffer, "ntSetInformationThread", &info->syscalls.ntSetInformationThread); 53 | dump_api_entry(buffer, "ntQueryInformationProcess", &info->syscalls.ntQueryInformationProcess); 54 | dump_api_entry(buffer, "ntQueryInformationThread", &info->syscalls.ntQueryInformationThread); 55 | dump_api_entry(buffer, "ntOpenSection", &info->syscalls.ntOpenSection); 56 | dump_api_entry(buffer, "ntAdjustPrivilegesToken", &info->syscalls.ntAdjustPrivilegesToken); 57 | dump_api_entry(buffer, "ntDeviceIoControlFile", &info->syscalls.ntDeviceIoControlFile); 58 | dump_api_entry(buffer, "ntWaitForMultipleObjects", &info->syscalls.ntWaitForMultipleObjects); 59 | 60 | BeaconFormatPrintf(buffer, "\nRun Time Library Functions:\n"); 61 | dump_rtl_entry(buffer, "rtlDosPathNameToNtPathNameUWithStatusAddr", info->rtls.rtlDosPathNameToNtPathNameUWithStatusAddr); 62 | dump_rtl_entry(buffer, "rtlFreeHeapAddr", info->rtls.rtlFreeHeapAddr); 63 | dump_rtl_entry(buffer, "rtlGetProcessHeapAddr", info->rtls.rtlGetProcessHeapAddr); 64 | } 65 | 66 | /* entry point */ 67 | void go(char * args, int alen) { 68 | formatp buffer; 69 | int size = 0; 70 | BEACON_SYSCALLS info = {0}; 71 | BOOL status; 72 | 73 | /* Allocate space for formatted output buffer */ 74 | BeaconFormatAlloc(&buffer, 8 * 1024); 75 | 76 | /* Generate the output */ 77 | status = BeaconGetSyscallInformation(&info, sizeof(BEACON_SYSCALLS), TRUE); 78 | if (status) { 79 | dump_syscalls(&buffer, &info); 80 | } else { 81 | BeaconFormatPrintf(&buffer, "Failed to get the system call information"); 82 | } 83 | 84 | /* Send the buffer of information with */ 85 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&buffer, &size)); 86 | 87 | 88 | /* Cleanup */ 89 | BeaconFormatFree(&buffer); 90 | } 91 | -------------------------------------------------------------------------------- /examples/cs_beacon_syscalls/cs_beacon_syscalls_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../beacon.h" 3 | 4 | void systemCallTestMemory(formatp * outBuffer) { 5 | LPVOID buffer = NULL; 6 | SIZE_T size = 0x1000 * 2; 7 | DWORD oldProtection = 0; 8 | 9 | BeaconFormatPrintf(outBuffer, "Running System Call Test Memory\n"); 10 | 11 | /* Allocate some memory to test with */ 12 | buffer = BeaconVirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 13 | if (!buffer) { 14 | BeaconPrintf(CALLBACK_ERROR, "Failed to allocate %lu bytes of memory\n"); 15 | } 16 | BeaconFormatPrintf(outBuffer, "Allocated memory at %p with protection set to %x\n", buffer, PAGE_READWRITE); 17 | 18 | /* Change protection on a page to be PAGE_EXECUTE_READ */ 19 | if (!BeaconVirtualProtect(buffer, 0x1000, PAGE_EXECUTE_READ, &oldProtection)) { 20 | BeaconPrintf(CALLBACK_ERROR, "Failed to protect the page of memory\n"); 21 | } 22 | BeaconFormatPrintf(outBuffer, "Protected memory at %p with protection set to %x previous protection %x\n", buffer, PAGE_EXECUTE_READ, oldProtection); 23 | 24 | /* Change protection on a page to be PAGE_EXECUTE_READ */ 25 | if (!BeaconVirtualProtect(buffer, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtection)) { 26 | BeaconPrintf(CALLBACK_ERROR, "Failed to protect the page of memory\n"); 27 | } 28 | BeaconFormatPrintf(outBuffer, "Protected memory at %p with protection set to %x previous protection %x\n", buffer, PAGE_EXECUTE_READWRITE, oldProtection); 29 | 30 | /* Cleanup */ 31 | if (!BeaconVirtualFree(buffer, 0, MEM_RELEASE)) { 32 | BeaconPrintf(CALLBACK_ERROR, "Failed to free the page of memory at %p\n", buffer); 33 | } 34 | BeaconFormatPrintf(outBuffer, "Released memory at %p\n", buffer); 35 | } 36 | 37 | /* entry point */ 38 | void go(char * args, int alen) { 39 | formatp outBuffer; 40 | 41 | /* Allocate space for formatted output buffer */ 42 | BeaconFormatAlloc(&outBuffer, 8 * 1024); 43 | 44 | BeaconPrintf(CALLBACK_OUTPUT, "Running Beacon System Calls Test Examples"); 45 | 46 | systemCallTestMemory(&outBuffer); 47 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&outBuffer, NULL)); 48 | } 49 | -------------------------------------------------------------------------------- /examples/cs_format_example/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- cs_format_example.c /Focs_format_example.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/cs_format_example/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c cs_format_example.c -o cs_format_example.x86.o 4 | x86_64-w64-mingw32-gcc -c cs_format_example.c -o cs_format_example.x64.o 5 | -------------------------------------------------------------------------------- /examples/cs_format_example/cs_format_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../beacon.h" 3 | 4 | void LoopExampleWithFormatting() { 5 | // Create the new buffer pointer 6 | formatp buffer; 7 | 8 | // Allocate memory to hold the formatted data 9 | BeaconFormatAlloc(&buffer, 1024); 10 | 11 | for(int i = 0; i < 5; i++) { 12 | // Instead of printing, we will now fill the buffer - notice the new line char 13 | BeaconFormatPrintf(&buffer, "counter is currently at %d\n", i); 14 | } 15 | 16 | // Now that we have the buffer filled up, let's print it out 17 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&buffer, NULL)); 18 | 19 | // Clean up 20 | BeaconFormatFree(&buffer); 21 | } 22 | 23 | void LoopExample() { 24 | for(int i = 0; i < 5; i++) { 25 | BeaconPrintf(CALLBACK_OUTPUT, "counter is currently at %d", i); 26 | } 27 | } 28 | 29 | void go_format(char *args, int len) { 30 | LoopExampleWithFormatting(); 31 | } 32 | 33 | void go(char *args, int len) { 34 | LoopExample(); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /examples/cs_format_example/cs_format_example.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "cs_format_example", 3 | "Used to display example output with or without formatting", 4 | 5 | "Used to display example output with or without formatting\n\n" . 6 | 7 | "Usage:\n" . 8 | " cs_format_example [options]\n\n" . 9 | 10 | "Arguments:\n" . 11 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 12 | 13 | "Options:\n" . 14 | " --format [yes|no] - do additional formatting of output. Default is no\n\n" . 15 | 16 | "Examples:\n" . 17 | " cs_format_example\n" . 18 | " cs_format_example --format yes\n\n" 19 | ); 20 | 21 | alias cs_format_example { 22 | local('$bid $format_arg $format_val'); 23 | 24 | ($bid, $format_arg, $format_val) = @_; 25 | 26 | if (($format_arg eq "--format") && ($format_val eq "yes")) { 27 | btask($bid, "Loop Example with formatting BOF"); 28 | run_example($bid, "go_format"); 29 | } else { 30 | btask($bid, "Loop Example with no formatting BOF"); 31 | run_example($bid, "go"); 32 | } 33 | } 34 | 35 | # Arguments 36 | # $1 - beacon id 37 | # $2 - entry point (function name) 38 | sub run_example { 39 | local('$bid $entry_point $barch $handle $data $args'); 40 | 41 | ($bid, $entry_point) = @_; 42 | 43 | # figure out the arch of this session 44 | $barch = barch($bid); 45 | 46 | # read in the right BOF file 47 | $handle = openf(script_resource("cs_format_example. $+ $barch $+ .o")); 48 | $data = readb($handle, -1); 49 | closef($handle); 50 | 51 | # execute it. 52 | beacon_inline_execute($bid, $data, $entry_point, $null); 53 | } 54 | -------------------------------------------------------------------------------- /examples/cs_key_value/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- cs_key_value.c /Focs_key_value.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/cs_key_value/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c cs_key_value.c -o cs_key_value.x86.o 4 | x86_64-w64-mingw32-gcc -c cs_key_value.c -o cs_key_value.x64.o 5 | -------------------------------------------------------------------------------- /examples/cs_key_value/cs_key_value.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../beacon.h" 3 | 4 | WINBASEAPI void * WINAPI KERNEL32$HeapAlloc (HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); 5 | WINBASEAPI void * WINAPI KERNEL32$HeapFree (HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); 6 | WINBASEAPI HANDLE WINAPI KERNEL32$GetProcessHeap(); 7 | 8 | #define HeapAlloc KERNEL32$HeapAlloc 9 | #define HeapFree KERNEL32$HeapFree 10 | #define GetProcessHeap KERNEL32$GetProcessHeap 11 | 12 | typedef struct { 13 | char *entry1; 14 | char *entry2; 15 | } MYDATA, *PMYDATA; 16 | 17 | 18 | void fill(char * buffer, char c, int len) { 19 | if (buffer == NULL || len == 0) { 20 | return; 21 | } 22 | 23 | while(len--) { 24 | buffer[len] = c; 25 | } 26 | } 27 | 28 | void cleanup_mydata(formatp *buffer, PMYDATA data) { 29 | if (data == NULL) { 30 | return; 31 | } 32 | 33 | BeaconFormatPrintf(buffer, "HeapFree entry1 at %p\n", data->entry1); 34 | fill(data->entry1, '\0', 9); 35 | HeapFree(GetProcessHeap(), 0, data->entry1); 36 | data->entry1 = NULL; 37 | 38 | BeaconFormatPrintf(buffer, "HeapFree entry2 at %p\n", data->entry2); 39 | fill(data->entry2, '\0', 9); 40 | HeapFree(GetProcessHeap(), 0, data->entry2); 41 | data->entry2 = NULL; 42 | 43 | BeaconFormatPrintf(buffer, "HeapFree data at %p\n", data); 44 | HeapFree(GetProcessHeap(), 0, data); 45 | } 46 | 47 | /* entry point */ 48 | void go(char * args, int alen) { 49 | datap parser; 50 | formatp buffer; 51 | char * state; 52 | char * key; 53 | PMYDATA data = NULL; 54 | 55 | /* parse the inputs (string) */ 56 | BeaconDataParse(&parser, args, alen); 57 | state = BeaconDataExtract(&parser, NULL); 58 | key = BeaconDataExtract(&parser, NULL); 59 | 60 | if (state == NULL) { 61 | BeaconPrintf(CALLBACK_ERROR, "The state is not set"); 62 | return; 63 | } 64 | 65 | /* Allocate space for formatted output buffer */ 66 | BeaconFormatAlloc(&buffer, 4096); 67 | 68 | BeaconFormatPrintf(&buffer, "Running the cs_key_value BOF with state: %s\n", state); 69 | 70 | if (state[0] == 'i') { 71 | /* Allocate memory for MYDATA */ 72 | data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MYDATA)); 73 | data->entry1 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 10); 74 | data->entry2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 10); 75 | 76 | /* initialize the data */ 77 | fill(data->entry1, 'a', 9); 78 | fill(data->entry2, 'b', 9); 79 | 80 | /* save the data to beacon's key/value store */ 81 | if (BeaconAddValue(key, data)) { 82 | BeaconFormatPrintf(&buffer, "Added key: %s at %p\n", key, data); 83 | } else { 84 | BeaconFormatPrintf(&buffer, "Unable to add key: %s at %p\n", key, data); 85 | cleanup_mydata(&buffer, data); 86 | } 87 | } 88 | else if (state[0] == 'c') { 89 | /* Get the data from beacon's key/value store */ 90 | data = BeaconGetValue(key); 91 | if (data == NULL) { 92 | BeaconFormatPrintf(&buffer, "Unable to get value for key: %s\n", key); 93 | } else { 94 | BeaconFormatPrintf(&buffer, "Found key: %s at %p\n", key, data); 95 | BeaconFormatPrintf(&buffer, "entry1: %s\n", data->entry1); 96 | BeaconFormatPrintf(&buffer, "entry2: %s\n", data->entry2); 97 | 98 | /* Change the data */ 99 | char c1 = data->entry1[0] + 1; 100 | char c2 = data->entry2[0] + 1; 101 | fill(data->entry1, c1, 5); 102 | fill(data->entry2, c2, 5); 103 | } 104 | 105 | } 106 | else if (state[0] == 'f') { 107 | /* Get the data to clean up the memory */ 108 | data = BeaconGetValue(key); 109 | if (data != NULL) { 110 | BeaconFormatPrintf(&buffer, "Found key: %s at %p\n", key, data); 111 | cleanup_mydata(&buffer, data); 112 | } 113 | 114 | /* Remove the key from beacon's key/value store */ 115 | if (BeaconRemoveValue(key)) { 116 | BeaconFormatPrintf(&buffer, "Removed key: %s\n", key); 117 | } else { 118 | BeaconFormatPrintf(&buffer, "Unable to remove key: %s\n", key); 119 | } 120 | } 121 | else { 122 | BeaconPrintf(CALLBACK_ERROR, "Unknown state"); 123 | } 124 | 125 | /* Send the buffer of information with */ 126 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&buffer, NULL)); 127 | 128 | /* Cleanup */ 129 | BeaconFormatFree(&buffer); 130 | } 131 | -------------------------------------------------------------------------------- /examples/cs_key_value/cs_key_value.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "cs_key_value", 3 | "Used to demonstrate the key value internal beacon APIs", 4 | 5 | "Used to demonstrate the key value internal beacon APIs\n\n" . 6 | 7 | "The cs_key_value BOF will take a key and state options to demonstrate\n" . 8 | "how you can add, get, or remove information to the beacon's key/value\n" . 9 | "store so it can be referenced by subsequent BOF executions or even a\n" . 10 | "different BOF that knows the key and data type. The 'init' state will\n" . 11 | "initialize a small data structure and add it to the key/value store.\n" . 12 | "The 'continue' state will get the data and modify it's contents based\n" . 13 | "on the current contents. The 'finish' state will get the data in order\n" . 14 | "to release the memory and remove the key from the key/value store.\n\n" . 15 | 16 | "Usage:\n" . 17 | " cs_key_value [options]\n\n" . 18 | 19 | "Arguments:\n" . 20 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 21 | 22 | "Options (specified in any order):\n" . 23 | " --key - specify a key name to use for the BOF\n" . 24 | " --state - specify which state to execute in the BOF\n" . 25 | " valid state: init, continue, and finish\n\n" . 26 | 27 | "Examples:\n" . 28 | " cs_key_value --key default --state init\n" . 29 | " cs_key_value --key default --state continue\n" . 30 | " cs_key_value --key default --state finish\n\n" 31 | ); 32 | 33 | alias cs_key_value { 34 | # Declare local variables 35 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $barch $handle $data $args'); 36 | 37 | # Set the defaults 38 | %opts["--state"] = "init"; 39 | %opts["--key"] = "default"; 40 | 41 | # Assign parameters to the opts hash map 42 | $bid = @_[0]; 43 | $opt_cnt = size(@_); 44 | @valid_opts = @("--state", "--key"); 45 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 46 | # Set the arg and value for this iteration 47 | $opt = @_[$opt_ind]; 48 | $opt_ind++; 49 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 50 | 51 | # Do some simple validation on opt and value 52 | if ($opt !in @valid_opts) { 53 | berror($bid, "$opt is not a valid option."); 54 | return; 55 | } 56 | if ($value is $null || $value in @valid_opts) { 57 | berror($bid, "Missing or invalid value for the $opt option."); 58 | return; 59 | } 60 | 61 | # Save the opt and value into the opts hash 62 | %opts[$opt] = $value; 63 | } 64 | 65 | # Validate options 66 | if (%opts["--state"] !in @("init", "continue", "finish")) { 67 | berror($bid, "state value is not valid: " . %opts["--state"]); 68 | return; 69 | } 70 | 71 | 72 | # figure out the arch of this session 73 | $barch = barch($bid); 74 | 75 | # read in the right BOF file 76 | $handle = openf(script_resource("cs_key_value. $+ $barch $+ .o")); 77 | $data = readb($handle, -1); 78 | closef($handle); 79 | 80 | # Pack our arguments 81 | $args = bof_pack($1, "zz", %opts["--state"], %opts["--key"]); 82 | 83 | # announce what we're doing 84 | btask($bid, "Running cs_key_value BOF using state: " . %opts["--state"] . " and key: " . %opts["--key"]); 85 | 86 | # execute it. 87 | beacon_inline_execute($bid, $data, "go", $args); 88 | } 89 | -------------------------------------------------------------------------------- /examples/cs_read_virtual_memory/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- cs_read_virtual_memory.c /Focs_read_virtual_memory.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/cs_read_virtual_memory/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c cs_read_virtual_memory.c -o cs_read_virtual_memory.x86.o 4 | x86_64-w64-mingw32-gcc -c cs_read_virtual_memory.c -o cs_read_virtual_memory.x64.o 5 | -------------------------------------------------------------------------------- /examples/cs_read_virtual_memory/cs_read_virtual_memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../beacon.h" 3 | 4 | //WINBASEAPI WINBOOL WINAPI KERNEL32$ReadProcessMemory (HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead); 5 | WINBASEAPI void *__cdecl MSVCRT$malloc(size_t _Size); 6 | WINBASEAPI void __cdecl MSVCRT$free(void *_Memory); 7 | 8 | #define malloc MSVCRT$malloc 9 | #define free MSVCRT$free 10 | 11 | HMODULE GetModHandle(LPCSTR module) { 12 | HMODULE hModule = GetModuleHandleA(module); 13 | return hModule ? hModule : LoadLibraryA(module); 14 | } 15 | 16 | LPVOID GetMemptr(LPCSTR module, LPCSTR function) { 17 | 18 | HMODULE hModule = GetModHandle(module); 19 | LPVOID memptr = GetProcAddress(hModule, function); 20 | return memptr ? memptr : NULL; 21 | } 22 | 23 | void ReadVirtualMemory(LPCSTR module, LPCSTR function, int len, int format) { 24 | formatp buffer; 25 | BYTE *readBuffer; 26 | SIZE_T bytesRead = 0; 27 | LPVOID memptr = GetMemptr(module, function); 28 | 29 | if (!memptr) { 30 | BeaconPrintf(CALLBACK_ERROR, "no memptr found"); 31 | return; 32 | } 33 | 34 | BeaconFormatAlloc(&buffer, 1024); 35 | 36 | 37 | readBuffer = malloc(len); 38 | #if 0 39 | KERNEL32$ReadProcessMemory((HANDLE) -1, memptr, readBuffer, len, &bytesRead); 40 | #else 41 | BeaconReadProcessMemory((HANDLE) -1, memptr, readBuffer, len, &bytesRead); 42 | #endif 43 | 44 | BeaconFormatPrintf(&buffer, "Showing the first %i opcodes of %s!%s\n", len, module, function); 45 | for (SIZE_T i = 0; i < bytesRead; ++i) { 46 | if (format) { 47 | BeaconFormatPrintf(&buffer, "\\x%02X", readBuffer[i]); 48 | } else { 49 | BeaconFormatPrintf(&buffer, "%02X", readBuffer[i]); 50 | } 51 | } 52 | 53 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&buffer, NULL)); 54 | 55 | BeaconFormatFree(&buffer); 56 | free(readBuffer); 57 | } 58 | 59 | void go(char *args, int argLen) { 60 | char * module; 61 | char * function; 62 | int len; 63 | int format; 64 | datap parser; 65 | 66 | BeaconDataParse(&parser, args, argLen); 67 | module = BeaconDataExtract(&parser, NULL); 68 | function = BeaconDataExtract(&parser, NULL); 69 | len = BeaconDataInt(&parser); 70 | format = BeaconDataInt(&parser); 71 | 72 | ReadVirtualMemory(module, function, len, format); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /examples/cs_read_virtual_memory/cs_read_virtual_memory.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "cs_read_virtual_memory", 3 | "Used to display example output with or without formatting", 4 | 5 | "Used to display example output with or without formatting\n\n" . 6 | 7 | "Usage:\n" . 8 | " cs_read_virtual_memory [module] [function] [length] [format]\n\n" . 9 | 10 | "Arguments:\n" . 11 | " \$1 - beacon id (CS automatically adds this argument)\n" . 12 | " \$2 - Module name\n" . 13 | " \$3 - Function name\n" . 14 | " \$4 - Length of bytes to read\n" . 15 | " \$5 - Format [0|1]\n\n" . 16 | 17 | 18 | "Examples:\n" . 19 | " cs_read_virtual_memory ntdll.dll EtwEventWrite 5 0\n" . 20 | " cs_read_virtual_memory ntdll.dll EtwEventWrite 5 1\n\n" 21 | ); 22 | 23 | alias cs_read_virtual_memory { 24 | local('$bid $module $function $length $format $barch $handle $data $args'); 25 | 26 | ($bid, $module, $function, $length, $format) = @_; 27 | 28 | # figure out the arch of this session 29 | $barch = barch($bid); 30 | 31 | # read in the right BOF file 32 | $handle = openf(script_resource("cs_read_virtual_memory. $+ $barch $+ .o")); 33 | $data = readb($handle, -1); 34 | closef($handle); 35 | 36 | $args = bof_pack($bid, "zzii", $module, $function, $length, $format); 37 | 38 | # execute it. 39 | beacon_inline_execute($bid, $data, "go", $args); 40 | } 41 | -------------------------------------------------------------------------------- /examples/demo/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- demo.c /Fodemo.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/demo/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c demo.c -o demo.x86.o 4 | x86_64-w64-mingw32-gcc -c demo.c -o demo.x64.o 5 | -------------------------------------------------------------------------------- /examples/demo/demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../beacon.h" 3 | 4 | WINBASEAPI int WINAPI KERNEL32$lstrlenA (LPCSTR lpString); 5 | 6 | 7 | int gCount = 5; 8 | int gxCount = 0; 9 | char * gBuffer = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx"; 10 | char * gStrList[] = {"gggg", "5555", "ssss", "zzzz"}; 11 | int gStrListSize = sizeof(gStrList) / sizeof(char *); 12 | 13 | /* int gzCount; // not supported instead use int gzCount = 0; */ 14 | 15 | /* function to take the src and modify it by some offset and 16 | * save it into the dest buffer. 17 | * 18 | * returns number of characters modified. 19 | */ 20 | int somefunc(char *src, char *dest, int destLen, int offset) { 21 | int i; 22 | for(i = 0; i < destLen && src[i] != 0x0; i++) { 23 | dest[i] = src[i] + offset; 24 | } 25 | ++gCount; 26 | return i; 27 | } 28 | 29 | /* function to print an array of strings. 30 | */ 31 | void printStrList(formatp *buffer, char *name, char **list, int count) { 32 | BeaconFormatPrintf(buffer, "listName: %s length: %d\n", name, count); 33 | for (int i = 0; i < count; i++) { 34 | BeaconFormatPrintf(buffer, "%s[%d] %s\n", name, i, list[i]); 35 | } 36 | gxCount++; 37 | } 38 | 39 | /* entry point */ 40 | void go(char * args, int alen) { 41 | datap parser; 42 | formatp buffer; 43 | char * str_arg; 44 | int num_arg; 45 | int result; 46 | char stuff1[40] = "AAAAAAAABBBBBBBBCCCCCCCC"; 47 | char stuff2[20] = { 'Z', 'Z', 'Z', 'Z', 'Z', 'Y', 'Y', 'Y', 'Y', 'Y', 'X', 'X', 'X', 'X', 'X', 'W', 'W', 'W', 'W', 0x0 }; 48 | char * lStrList[] = {"123", "456", "789", "abc"}; 49 | int lStrListSize = sizeof(lStrList) / sizeof(char *); 50 | 51 | 52 | BeaconDataParse(&parser, args, alen); 53 | str_arg = BeaconDataExtract(&parser, NULL); 54 | num_arg = BeaconDataInt(&parser); 55 | 56 | /* Allocate space for formatted output buffer */ 57 | BeaconFormatAlloc(&buffer, 1024); 58 | 59 | BeaconFormatPrintf(&buffer, "gCount: %d gxGount: %d\n", gCount, gxCount); 60 | 61 | BeaconFormatPrintf(&buffer, "Args[0]: %s Args[1]: %d\n", str_arg, num_arg); 62 | 63 | ++gCount; 64 | ++gxCount; 65 | BeaconFormatPrintf(&buffer, "[stuff1 before] %d %s\n", sizeof(stuff1), stuff1); 66 | result = somefunc(str_arg, stuff1, sizeof(stuff1), 1); 67 | BeaconFormatPrintf(&buffer, "[stuff1 after ] %d %s\n", result, stuff1); 68 | BeaconFormatPrintf(&buffer, "gCount: %d gxGount: %d\n", gCount, gxCount); 69 | 70 | BeaconFormatPrintf(&buffer, "[stuff2 before] %d %s\n", sizeof(stuff2), stuff2); 71 | result = somefunc(stuff2, stuff2, sizeof(stuff2), 1); 72 | BeaconFormatPrintf(&buffer, "[stuff2 after ] %d %s\n", result, stuff2); 73 | 74 | printStrList(&buffer, "lStrList", lStrList, lStrListSize); 75 | printStrList(&buffer, "gStrList", gStrList, gStrListSize); 76 | 77 | ++gCount; 78 | BeaconFormatPrintf(&buffer, "[gBuffer before] %d %s\n", KERNEL32$lstrlenA(gBuffer), gBuffer); 79 | result = somefunc(stuff1, gBuffer, KERNEL32$lstrlenA(gBuffer), -1); 80 | BeaconFormatPrintf(&buffer, "[gBuffer after ] %d %s\n", result, gBuffer); 81 | BeaconFormatPrintf(&buffer, "gCount: %d gxGount: %d\n", gCount, gxCount); 82 | 83 | 84 | /* Send the buffer of information with BeaconPrintf */ 85 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&buffer, NULL)); 86 | 87 | } 88 | 89 | -------------------------------------------------------------------------------- /examples/demo/demo.cna: -------------------------------------------------------------------------------- 1 | 2 | # $1 - beacon id 3 | alias demo { 4 | local('$barch $handle $data $args'); 5 | 6 | # figure out the arch of this session 7 | $barch = barch($1); 8 | 9 | # read in the right BOF file 10 | $handle = openf(script_resource("demo. $+ $barch $+ .o")); 11 | $data = readb($handle, -1); 12 | closef($handle); 13 | 14 | # pack our arguments 15 | $args = bof_pack($1, "zi", "Hello beacon", 1234); 16 | 17 | # announce what we're doing 18 | btask($1, "Running demo BOF"); 19 | 20 | # execute it. 21 | beacon_inline_execute($1, $data, "go", $args); 22 | } 23 | -------------------------------------------------------------------------------- /examples/hello/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- hello.c /Fohello.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/hello/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c hello.c -o hello.x86.o 4 | x86_64-w64-mingw32-gcc -c hello.c -o hello.x64.o 5 | -------------------------------------------------------------------------------- /examples/hello/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../../beacon.h" 5 | 6 | void demo(char * args, int length) { 7 | datap parser; 8 | char * str_arg; 9 | int num_arg; 10 | 11 | BeaconDataParse(&parser, args, length); 12 | str_arg = BeaconDataExtract(&parser, NULL); 13 | num_arg = BeaconDataInt(&parser); 14 | 15 | BeaconPrintf(CALLBACK_OUTPUT, "Message is %s with %d arg", str_arg, num_arg); 16 | } 17 | -------------------------------------------------------------------------------- /examples/hello/hello.cna: -------------------------------------------------------------------------------- 1 | alias hello { 2 | local('$barch $handle $data $args'); 3 | 4 | # figure out the arch of this session 5 | $barch = barch($1); 6 | 7 | # read in the right BOF file 8 | $handle = openf(script_resource("hello. $+ $barch $+ .o")); 9 | $data = readb($handle, -1); 10 | closef($handle); 11 | 12 | # pack our arguments 13 | $args = bof_pack($1, "zi", "Hello World", 1234); 14 | 15 | # announce what we're doing 16 | btask($1, "Running Hello BOF"); 17 | 18 | # execute it. 19 | beacon_inline_execute($1, $data, "demo", $args); 20 | } 21 | -------------------------------------------------------------------------------- /examples/helloWorld/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- hello.c /Fohello.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/helloWorld/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c hello.c -o hello.x86.o 4 | x86_64-w64-mingw32-gcc -c hello.c -o hello.x64.o 5 | -------------------------------------------------------------------------------- /examples/helloWorld/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../beacon.h" 3 | 4 | void go(char * args, int alen) { 5 | BeaconPrintf(CALLBACK_OUTPUT, "Hello World: %s", args); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # BOF Template 2 | 3 | This repository is meant to host the core files needed to create a Beacon 4 | Object File for use with Cobalt Strike. 5 | 6 | A Beacon Object File (BOF) is a compiled C program, written to a convention 7 | that allows it to execute within a Beacon process and use internal Beacon APIs. 8 | BOFs are a way to rapidly extend the Beacon agent with new post-exploitation 9 | features. 10 | 11 | ## beacon.h 12 | 13 | beacon.h contains definitions for several internal Beacon APIs. The function go 14 | is similar to main in any other C program. It's the function that's called by 15 | inline-execute and arguments are passed to it. BeaconOutput is an internal 16 | Beacon API to send output to the operator. 17 | 18 | ## examples 19 | This directory contains examples BOFs. The directory contains the following: 20 | 21 | #### cs_beacon_info 22 | Directory containing the cs_beacon_info BOF which demonstrates 23 | BeaconInformation API introduced in 4.9 24 | 25 | - cs_beacon_info/build.bat - build script for the Microsoft Visual Studio compiler. 26 | - cs_beacon_info/build.sh - build script for the MinGW compiler. 27 | - cs_beacon_info/cs_beacon_info.c - source code for the cs_beacon_info example. 28 | - cs_beacon_info/cs_beacon_info.cna - aggressor script file to execute the cs_beacon_info command. 29 | 30 | Use: 31 | - Use one of the build scripts to build the object file. 32 | - Load the script - In Cobalt Strike -> Script Manager -> Load `cs_beacon_info/cs_beacon_info.cna` 33 | - Execute `help cs_beacon_info` for the help text. 34 | - Execute the `cs_beacon_info` command in the beacon console. 35 | 36 | #### cs_format_example 37 | Directory containing the cs_format_example BOF from the documentation 38 | 'Formatting BOF Output' 39 | 40 | - cs_format_example/build.bat - build script for the Microsoft Visual Studio compiler. 41 | - cs_format_example/build.sh - build script for the MinGW compiler. 42 | - cs_format_example/cs_format_example.c - source code for the cs_format_example example. 43 | - cs_format_example/cs_format_example.cna - aggressor script file to execute the cs_format_example command. 44 | 45 | Use: 46 | - Use one of the build scripts to build the object file. 47 | - Load the script - In Cobalt Strike -> Script Manager -> Load `cs_format_example/cs_format_example.cna` 48 | - Execute `help cs_format_example` for the help text. 49 | - Execute the `cs_format_example` or `cs-format_example --format yes` command in the beacon console. 50 | 51 | #### cs_key_value 52 | Directory containing the cs_key_value BOF which demonstrates the Key/Value 53 | store APIs introduced in 4.9 54 | 55 | - cs_key_value/build.bat - build script for the Microsoft Visual Studio compiler. 56 | - cs_key_value/build.sh - build script for the MinGW compiler. 57 | - cs_key_value/cs_key_value.c - source code for the cs_key_value example. 58 | - cs_key_value/cs_key_value.cna - aggressor script file to execute the cs_key_value command. 59 | 60 | Use: 61 | - Use one of the build scripts to build the object file. 62 | - Load the script - In Cobalt Strike -> Script Manager -> Load `cs_key_value/cs_key_value.cna` 63 | - Execute `help cs_key_value` for the help text. 64 | - Execute the following commands: 65 | ```` 66 | cs_key_value --key default --state init 67 | cs_key_value --key default --state continue 68 | cs_key_value --key default --state finish 69 | ```` 70 | 71 | #### cs_read_virtual_memory 72 | Directory containing the cs_read_virtual_memory BOF from the documentation 73 | 'Formatting BOF Output' 74 | 75 | - cs_read_virtual_memory/build.bat - build script for the Microsoft Visual Studio compiler. 76 | - cs_read_virtual_memory/build.sh - build script for the MinGW compiler. 77 | - cs_read_virtual_memory/cs_read_virtual_memory.c - source code for the cs_read_virtual_memory example. 78 | - cs_read_virtual_memory/cs_read_virtual_memory.cna - aggressor script file to execute the cs_read_virtual_memory command. 79 | 80 | Use: 81 | - Use one of the build scripts to build the object file. 82 | - Load the script - In Cobalt Strike -> Script Manager -> Load `cs_read_virtual_memory/cs_read_virtual_memory.cna` 83 | - Execute `help cs_read_virtual_memory` for the help text. 84 | - Execute the `cs_read_virtual_memory ntdll.dll EtwEventWrite 5 0` command in the beacon console. 85 | 86 | #### demo 87 | Directory containing the example demo BOF which demonstrates items that are now 88 | supported in Cobalt Strike version 4.7 89 | 90 | - demo/build.bat - build script for the Microsoft Visual Studio compiler. 91 | - demo/build.sh - build script for the MinGW compiler. 92 | - demo/demo.c - source code for the demo example. 93 | - demo/demo.cna - aggressor script file to execute the demo command. 94 | 95 | Use: 96 | - Use one of the build scripts to build the object file. 97 | - Load the script - In Cobalt Strike -> Script Manager -> Load `demo/demo.cna` 98 | - Execute the `demo` command in the beacon console. 99 | 100 | #### hello 101 | Directory containing the example hello world BOF from the documentation. 102 | - hello/build.bat - build script for the Microsoft Visual Studio compiler. 103 | - hello/build.sh - build script for the MinGW compiler. 104 | - hello/hello.c - source code for the hello world example. 105 | - hello/hello.cna - aggressor script file to execute the hello command. 106 | 107 | Use: 108 | - Use one of the build scripts to build the object file. 109 | - Load the script - In Cobalt Strike -> Script Manager -> Load `hello/hello.cna` 110 | - Execute the `hello` command in the beacon console. 111 | 112 | #### helloWorld 113 | Directory containing the example helloWorld BOF from the documentation. 114 | - helloWorld/build.bat - build script for the Microsoft Visual Studio compiler. 115 | - helloWorld/build.sh - build script for the MinGW compiler. 116 | - helloWorld/hello.c - source code for the example. 117 | 118 | Use: 119 | - Use one of the build scripts to build the object file. 120 | - Use the inline-execute command in the beacon console. 121 | 122 | Examples: 123 | ```` 124 | inline-execute /base/path/examples/helloWorld/hello.x64.o these are args 125 | inline-execute /base/path/examples/helloWorld/hello.x86.o these are args 126 | ```` 127 | 128 | ## tests 129 | 130 | The tests directory contains examples for using the internal Beacon APIs. The 131 | directory contains the following: 132 | 133 | - build.sh - builds the object files located in tests/src. Requires mingw-w64 cross-compiler package 134 | - bof_test_runner.cna - Aggressor script file for running the tests 135 | - src directory - Contains example source files for using the internal Beacon APIs. 136 | 137 | How to execute the tests: 138 | 1. Build the object files with the build.sh script in the tests directory. 139 | 2. Start a team server and client 140 | 3. Load the bof_test_runner.cna script from the tests directory. 141 | 4. Generate and start a beacon on a test system. 142 | 5. In the beacon console execute: run_boff_tests "" \ "" 143 | 144 | where: 145 | - user_string is any quoted input string 146 | - numeric is any signed short or integer value 147 | - numeric_string is any quoted numeric string (only used in testBeaconDataLongLong) 148 | 149 | ## BOF Documentation 150 | 151 | - https://www.cobaltstrike.com/help-beacon-object-files 152 | 153 | ## Community developed BOFs 154 | 155 | - https://cobalt-strike.github.io/community_kit/ 156 | 157 | -------------------------------------------------------------------------------- /tests/bof_test_runner.cna: -------------------------------------------------------------------------------- 1 | # Example BOF test runner script to test the internal beacon BOF functions 2 | # The alias run_boff_tests will run all of the defined tests 3 | # 4 | # Usage: run_boff_tests 5 | # 6 | # Example: 7 | # run_boff_tests "my user test string" 2022 8 | # 9 | 10 | # Helper function to execute a single test BOF 11 | # $1 - beacon id 12 | # $2 - base name of BOF to run 13 | # $3 - args to pass to BOF 14 | sub bof_test_runner { 15 | local('$barch $handle $data'); 16 | 17 | # figure out the arch of this session 18 | $barch = barch($1); 19 | 20 | # read the contents of the BOF 21 | $handle = openf(script_resource("obj/ $+ $2 $+ . $+ $barch $+ .o")); 22 | $data = readb($handle, -1); 23 | closef($handle); 24 | 25 | # announce what we're doing to the beacon and script consoles 26 | btask($1, "Running example BOF: $2"); 27 | println(formatDate("[HH:mm:ss] ") . "Running example BOF: $2"); 28 | 29 | # execute the BOF. 30 | beacon_inline_execute($1, $data, "go", $3); 31 | } 32 | 33 | # Test runner alias to execute the defined tests 34 | # $1 - beacon id 35 | # $2 - User test string to pass to the bof file 36 | # $3 - User test number to pass to the bof file 37 | # $4 - User test number as a string to pass to the bof file (only testBeaconDataLongLong) 38 | alias run_boff_tests { 39 | local('@tests @test'); 40 | 41 | # Define the tests to run 42 | @tests = @( 43 | @("testBeaconDataStrings", bof_pack($1, "zzz", $2, "Test Defined String", "Next Test Defined String")), 44 | @("testBeaconDataShorts", bof_pack($1, "ssssss", $3, $3, -32768, 32767, 0, 65535)), 45 | @("testBeaconDataIntegers", bof_pack($1, "iiiiii", $3, $3, -2147483648, 2147483647, 0, -1)), 46 | @("testBeaconDataMixDataTypes", bof_pack($1, "zis", $2, $3, $3)), 47 | @("testBeaconDataLongLong", bof_pack($1, "zi", $4, $3)), 48 | @("testBeaconOutput", bof_pack($1, "zi", $2, $3)), 49 | @("testBeaconPrintf", bof_pack($1, "zi", $2, $3)), 50 | @("testBeaconFormat", bof_pack($1, "zi", $2, $3)), 51 | @("testBeaconErrorD", $null), 52 | @("testBeaconErrorDD", $null), 53 | @("testBeaconErrorNA", $null) 54 | ); 55 | 56 | foreach @test (@tests) 57 | { 58 | bof_test_runner($1, @test[0], @test[1]); 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /tests/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | CC_x64="x86_64-w64-mingw32-gcc" 5 | CC_x86="i686-w64-mingw32-gcc" 6 | archs="x64 x86" 7 | 8 | compile() { 9 | for arch in ${archs} ; do 10 | if [ ! -f obj/${1}.${arch}.o -o src/${1}.c -nt obj/${1}.${arch}.o ] ; then 11 | echo "Compile obj/$1.${arch}.o" 12 | if [ "${arch}" == "x64" ] ; then 13 | ${CC_x64} -o obj/${1}.${arch}.o -c src/${1}.c -masm=intel -Wall -I../ 14 | else 15 | ${CC_x86} -o obj/${1}.${arch}.o -c src/${1}.c -masm=intel -Wall -I../ 16 | fi 17 | fi 18 | done 19 | } 20 | 21 | 22 | # main 23 | 24 | # check for a cross-compiler 25 | if [ ! $(command -v ${CC_x64}) ]; then 26 | echo "No cross-compiler detected. Try: apt-get install mingw-w64" 27 | exit 28 | fi 29 | 30 | [ -d obj ] || mkdir obj 31 | 32 | files=$(find src -name \*.c) 33 | for f in ${files} ; do 34 | compile $(basename ${f%.*}) 35 | done 36 | 37 | -------------------------------------------------------------------------------- /tests/src/testBeaconDataIntegers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | void go(char * args, int alen) { 6 | datap parser; 7 | int userInt, minInt, maxInt; 8 | unsigned int userUInt, minUInt, maxUInt; 9 | 10 | /* 11 | * Signed int support: 12 | * BeaconDataInt supports the numeric range: -2147483648 through 2147483647 13 | * 14 | * Unsigned int support: 15 | * (unsigned int) BeaconDataInt supports the numeric range: 0 through 4294967295 16 | * 17 | * However, the unsigned int range: 2147483648 through 4294967295 18 | * requires the use of unsigned int casting of the negative integer values 19 | * unsigned int 2147483648 == (unsigned int) -2147483648 20 | * unsigned int 4294967295 == (unsigned int) -1 21 | */ 22 | BeaconDataParse(&parser, args, alen); 23 | userInt = BeaconDataInt(&parser); 24 | userUInt = (unsigned int) BeaconDataInt(&parser); 25 | minInt = BeaconDataInt(&parser); 26 | maxInt = BeaconDataInt(&parser); 27 | minUInt = (unsigned int) BeaconDataInt(&parser); 28 | maxUInt = (unsigned int) BeaconDataInt(&parser); 29 | 30 | 31 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! Start testBeaconDataIntegers !!!!"); 32 | 33 | BeaconPrintf(CALLBACK_OUTPUT, "user defined signed int : %d", userInt); 34 | BeaconPrintf(CALLBACK_OUTPUT, "user defined unsigned int : %u", userUInt); 35 | 36 | BeaconPrintf(CALLBACK_OUTPUT, "signed int min : %d", minInt); 37 | BeaconPrintf(CALLBACK_OUTPUT, "signed int max : %d", maxInt); 38 | 39 | BeaconPrintf(CALLBACK_OUTPUT, "unsigned int min : %u", minUInt); 40 | BeaconPrintf(CALLBACK_OUTPUT, "unsigned int max : %u", maxUInt); 41 | 42 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconDataIntegers !!!!\n\n"); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /tests/src/testBeaconDataLongLong.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | WINBASEAPI long long __cdecl MSVCRT$_atoi64(CONST CHAR *); 6 | WINBASEAPI WINBOOL WINAPI SHLWAPI$StrToInt64ExA(LPCSTR, DWORD, LONGLONG *); 7 | 8 | void go(char * args, int alen) { 9 | datap parser; 10 | char *userString; 11 | int userStringLen; 12 | int userInt; 13 | long long testLongLong; 14 | long long testFromUserString = 0; 15 | 16 | BeaconDataParse(&parser, args, alen); 17 | userString = BeaconDataExtract(&parser, &userStringLen); 18 | userInt = BeaconDataInt(&parser); 19 | 20 | /* Take the userInt and do some calculations to set a long long value */ 21 | /* This is not a good way to set a value with a data type long long. */ 22 | testLongLong = (long long) userInt * 6; 23 | 24 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! Start testBeaconDataLongLong !!!!"); 25 | 26 | 27 | BeaconPrintf(CALLBACK_OUTPUT, "signed userInt : %d", userInt); 28 | BeaconPrintf(CALLBACK_OUTPUT, "long long : %lld = (%d * 6)", testLongLong, userInt); 29 | 30 | BeaconPrintf(CALLBACK_OUTPUT, "long long max : %lld", LLONG_MAX); 31 | BeaconPrintf(CALLBACK_OUTPUT, "unsigned long long max : %llu", ULLONG_MAX); 32 | 33 | /* Convert the userString to a long long instead. */ 34 | if (SHLWAPI$StrToInt64ExA(userString, 0x0, &testFromUserString)) { 35 | BeaconPrintf(CALLBACK_OUTPUT, "userString -> long long : %lld", testFromUserString); 36 | BeaconPrintf(CALLBACK_OUTPUT, "userString -> unsigned long long : %llu", (unsigned long long) testFromUserString); 37 | } else { 38 | BeaconPrintf(CALLBACK_ERROR, "userString '%s' is not a valid for conversion", userString); 39 | } 40 | 41 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconDataLongLong !!!!\n\n"); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /tests/src/testBeaconDataMixDataTypes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | void go(char * args, int alen) { 6 | datap parser; 7 | char *userString; 8 | int userStringLen; 9 | int userInt; 10 | short userShort; 11 | 12 | BeaconDataParse(&parser, args, alen); 13 | userString = BeaconDataExtract(&parser, &userStringLen); 14 | userInt = BeaconDataInt(&parser); 15 | userShort = BeaconDataShort(&parser); 16 | 17 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! Start testBeaconDataMixDataTypes !!!!"); 18 | 19 | BeaconPrintf(CALLBACK_OUTPUT, "User string : '%s' has %d characters", userString, userStringLen); 20 | 21 | BeaconPrintf(CALLBACK_OUTPUT, "User signed int : %d", userInt); 22 | BeaconPrintf(CALLBACK_OUTPUT, "User unsigned int : %u", (unsigned int) userInt); 23 | BeaconPrintf(CALLBACK_OUTPUT, "User signed short : %hi", userShort); 24 | BeaconPrintf(CALLBACK_OUTPUT, "User unsigned short : %hu", (unsigned short) userShort); 25 | 26 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconDataMixDataTypes !!!!\n\n"); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /tests/src/testBeaconDataShorts.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | void go(char * args, int alen) { 6 | datap parser; 7 | short userShort, minShort, maxShort; 8 | unsigned short userUShort, minUShort, maxUShort; 9 | 10 | /* 11 | * Signed short support: 12 | * BeaconDataShort supports the numeric range: -32768 through 32767 13 | * 14 | * Unsigned short support: 15 | * (unsigned short) BeaconDataShort supports the numeric range: 0 through 65535 16 | * 17 | */ 18 | BeaconDataParse(&parser, args, alen); 19 | userShort = BeaconDataShort(&parser); 20 | userUShort = (unsigned short) BeaconDataShort(&parser); 21 | minShort = BeaconDataShort(&parser); 22 | maxShort = BeaconDataShort(&parser); 23 | minUShort = (unsigned short) BeaconDataShort(&parser); 24 | maxUShort = (unsigned short) BeaconDataShort(&parser); 25 | 26 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! Start testBeaconDataShorts !!!!"); 27 | 28 | BeaconPrintf(CALLBACK_OUTPUT, "user defined signed short : %hi", userShort); 29 | BeaconPrintf(CALLBACK_OUTPUT, "user defined unsigned short : %hu", userUShort); 30 | 31 | BeaconPrintf(CALLBACK_OUTPUT, "signed short min : %hi", minShort); 32 | BeaconPrintf(CALLBACK_OUTPUT, "signed short max : %hi", maxShort); 33 | 34 | BeaconPrintf(CALLBACK_OUTPUT, "unsigned short min : %hu", minUShort); 35 | BeaconPrintf(CALLBACK_OUTPUT, "unsigned short max : %hu", maxUShort); 36 | 37 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconDataShorts !!!!\n\n"); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /tests/src/testBeaconDataStrings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | void go(char * args, int alen) { 6 | datap parser; 7 | char *string1, *string2, *string3; 8 | int string1Len, string2Len; 9 | 10 | BeaconDataParse(&parser, args, alen); 11 | /* Examples of extracting the string and length */ 12 | string1 = BeaconDataExtract(&parser, &string1Len); 13 | string2 = BeaconDataExtract(&parser, &string2Len); 14 | 15 | /* Example of extracting just the string if you do not need the length */ 16 | string3 = BeaconDataExtract(&parser, NULL); 17 | 18 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! Start testBeaconDataStrings !!!!"); 19 | 20 | BeaconPrintf(CALLBACK_OUTPUT, "User string: '%s' has %d characters", string1, string1Len); 21 | BeaconPrintf(CALLBACK_OUTPUT, "Test string: '%s' has %d characters", string2, string2Len); 22 | BeaconPrintf(CALLBACK_OUTPUT, "Test string: '%s' string length was not extracted.", string3); 23 | 24 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconDataStrings !!!!\n\n"); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tests/src/testBeaconErrorD.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | /* 6 | Internal functions which are not publicly documented 7 | Reason is the message strings that are displayed by 8 | this function can not be modified other than the 9 | integer that is passed in. 10 | Can be used if the message text works for your case 11 | */ 12 | DECLSPEC_IMPORT void BeaconErrorD(int type, int arg1); 13 | 14 | void go(char * args, int alen) { 15 | 16 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! testBeaconErrorD !!!!"); 17 | 18 | BeaconErrorD(0x07, 1234); 19 | BeaconErrorD(0x08, 1234); 20 | BeaconErrorD(0x09, 1234); 21 | BeaconErrorD(0x0a, 1234); 22 | BeaconErrorD(0x0b, 1234); 23 | BeaconErrorD(0x0c, 1234); 24 | BeaconErrorD(0x0d, 1234); 25 | BeaconErrorD(0x0e, 1234); 26 | BeaconErrorD(0x0f, 1234); 27 | BeaconErrorD(0x10, 1234); 28 | BeaconErrorD(0x11, 1234); 29 | BeaconErrorD(0x12, 1234); 30 | BeaconErrorD(0x13, 1234); 31 | BeaconErrorD(0x14, 1234); 32 | BeaconErrorD(0x15, 1234); 33 | BeaconErrorD(0x16, 1234); 34 | BeaconErrorD(0x17, 1234); 35 | BeaconErrorD(0x18, 1234); 36 | BeaconErrorD(0x19, 1234); 37 | BeaconErrorD(0x1a, 1234); 38 | BeaconErrorD(0x1b, 1234); 39 | BeaconErrorD(0x1c, 1234); 40 | BeaconErrorD(0x1d, 1234); 41 | BeaconErrorD(0x3f, 1234); 42 | BeaconErrorD(0x41, 1234); 43 | BeaconErrorD(0x47, 1234); 44 | BeaconErrorD(0x49, 1234); 45 | BeaconErrorD(0x4f, 1234); 46 | 47 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconErrorD !!!!\n\n"); 48 | } 49 | 50 | -------------------------------------------------------------------------------- /tests/src/testBeaconErrorDD.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | /* 6 | Internal functions which are not publicly documented 7 | Reason is the message strings that are displayed by 8 | this function can not be modified other than the 9 | integer that is passed in. 10 | Can be used if the message text works for your case 11 | */ 12 | DECLSPEC_IMPORT void BeaconErrorDD(int type, int arg1, int arg2); 13 | 14 | void go(char * args, int alen) { 15 | 16 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! Start testBeaconErrorDD !!!!"); 17 | 18 | BeaconErrorDD(0x1e, 123456, 20); 19 | BeaconErrorDD(0x1f, 123456, 20); 20 | BeaconErrorDD(0x20, 123456, 20); 21 | BeaconErrorDD(0x21, 123456, 20); 22 | BeaconErrorDD(0x22, 123456, 20); 23 | BeaconErrorDD(0x23, 123456, 20); 24 | BeaconErrorDD(0x24, 123456, 20); 25 | BeaconErrorDD(0x25, 123456, 20); 26 | BeaconErrorDD(0x26, 123456, 20); 27 | BeaconErrorDD(0x27, 123456, 20); 28 | BeaconErrorDD(0x48, 123456, 20); 29 | 30 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconErrorDD !!!!\n\n"); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /tests/src/testBeaconErrorNA.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | /* 6 | Internal functions which are not publicly documented 7 | Reason is the message strings that are displayed by 8 | this function can not be modified other than the 9 | integer that is passed in. 10 | Can be used if the message text works for your case 11 | */ 12 | DECLSPEC_IMPORT void BeaconErrorNA(int type); 13 | 14 | void go(char * args, int alen) { 15 | 16 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! testBeaconErrorNA (No Arguments) !!!!"); 17 | 18 | BeaconErrorNA(0x01); 19 | BeaconErrorNA(0x02); 20 | BeaconErrorNA(0x03); 21 | BeaconErrorNA(0x04); 22 | BeaconErrorNA(0x05); 23 | BeaconErrorNA(0x06); 24 | BeaconErrorNA(0x3b); 25 | BeaconErrorNA(0x3e); 26 | BeaconErrorNA(0x40); 27 | BeaconErrorNA(0x42); 28 | BeaconErrorNA(0x43); 29 | BeaconErrorNA(0x44); 30 | BeaconErrorNA(0x46); 31 | BeaconErrorNA(0x4b); 32 | BeaconErrorNA(0x4d); 33 | BeaconErrorNA(0x4e); 34 | 35 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconErrorNA (No Arguments) !!!!\n\n"); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /tests/src/testBeaconFormat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | 6 | void go(char * args, int alen) { 7 | datap parser; 8 | formatp buffer; 9 | char * userString; 10 | int userStringLen = 0; 11 | int userInt; 12 | char * bufferString; 13 | int bufferStringLen; 14 | 15 | /* Parse the parameters */ 16 | BeaconDataParse(&parser, args, alen); 17 | userString = BeaconDataExtract(&parser, &userStringLen); 18 | userInt = BeaconDataInt(&parser); 19 | 20 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! Start testBeaconFormat !!!!"); 21 | 22 | /* Allocate space for our buffer */ 23 | BeaconFormatAlloc(&buffer, 1024); 24 | 25 | /* Build up a buffer of information */ 26 | BeaconFormatPrintf(&buffer, "BeaconFormat test with end of string (EOS) issue:\n"); 27 | BeaconFormatPrintf(&buffer, "The user passed in the integer: %d\n", userInt); 28 | BeaconFormatPrintf(&buffer, "The user passed in the string: "); 29 | BeaconFormatAppend(&buffer, userString, userStringLen); 30 | BeaconFormatPrintf(&buffer, "Do you see this string? No because the EOS was copied over as well.\n"); 31 | 32 | /* Send the buffer of information with BeaconPrintf */ 33 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&buffer, NULL)); 34 | 35 | 36 | /* Reset and do the same thing again but resolve the EOS issue */ 37 | BeaconFormatReset(&buffer); 38 | BeaconFormatPrintf(&buffer, "BeaconFormat test with end of string (EOS) issue resolved:\n"); 39 | BeaconFormatPrintf(&buffer, "The user passed in the integer: %d\n", userInt); 40 | BeaconFormatPrintf(&buffer, "The user passed in the string: "); 41 | BeaconFormatAppend(&buffer, userString, userStringLen - 1); 42 | BeaconFormatPrintf(&buffer, "\nDo you see this string? Yes because the EOS was not copied.\n"); 43 | 44 | /* Send the buffer of information with BeaconPrintf */ 45 | BeaconPrintf(CALLBACK_OUTPUT, "%s\n", BeaconFormatToString(&buffer, NULL)); 46 | 47 | 48 | /* Reset the buffer and format the information differently */ 49 | BeaconFormatReset(&buffer); 50 | BeaconFormatPrintf(&buffer, "BeaconFormat test formating the information differently.\n"); 51 | BeaconFormatPrintf(&buffer, "Input String (%d): %s\nInput Integer: %d\n", userStringLen, userString, userInt); 52 | 53 | /* Send the buffer of information with BeaconOutput */ 54 | bufferString = BeaconFormatToString(&buffer, &bufferStringLen); 55 | BeaconOutput(CALLBACK_OUTPUT, bufferString, bufferStringLen); 56 | 57 | 58 | /* Reset the buffer and see how BeaconFormatInt works */ 59 | /* The BeaconFormatInt function is for internal use and is not useful for external BOFs */ 60 | BeaconFormatReset(&buffer); 61 | BeaconFormatPrintf(&buffer, "BeaconFormat using BeaconFormatInt\n"); 62 | BeaconFormatPrintf(&buffer, "Appending 3 test integers: "); 63 | BeaconFormatInt(&buffer, 65); // ASCII - A 64 | BeaconFormatInt(&buffer, 32); // ASCII - SPACE 65 | BeaconFormatInt(&buffer, 66); // ASCII - B 66 | BeaconFormatPrintf(&buffer, "\nDo you see this string? Yes because BeaconFormatInt does not add an EOS.\n"); 67 | 68 | /* Send the buffer of information with BeaconOutput */ 69 | bufferString = BeaconFormatToString(&buffer, &bufferStringLen); 70 | BeaconOutput(CALLBACK_OUTPUT, bufferString, bufferStringLen); 71 | 72 | /* Cleanup */ 73 | BeaconFormatFree(&buffer); 74 | 75 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconFormat !!!!\n\n"); 76 | } 77 | 78 | -------------------------------------------------------------------------------- /tests/src/testBeaconOutput.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | 6 | void go(char * args, int alen) { 7 | datap parser; 8 | char * userString; 9 | int userStringLen = 0; 10 | 11 | /* Parse the parameters */ 12 | BeaconDataParse(&parser, args, alen); 13 | userString = BeaconDataExtract(&parser, &userStringLen); 14 | 15 | BeaconOutput(CALLBACK_OUTPUT, "!!!! Start testBeaconOutput !!!!", 32); 16 | 17 | BeaconOutput(CALLBACK_OUTPUT, "Next three outputs represent the user supplied string using the three output types", 84); 18 | BeaconOutput(CALLBACK_OUTPUT, userString, userStringLen); 19 | BeaconOutput(CALLBACK_OUTPUT_OEM, userString, userStringLen); 20 | BeaconOutput(CALLBACK_OUTPUT_UTF8, userString, userStringLen); 21 | 22 | /* Hello world string in Japanese, CALLBACK_OUTPUT_UTF8 is the correct ouput type */ 23 | BeaconOutput(CALLBACK_OUTPUT, "Next three outputs represent 'Hello world' in Japanese using the 3 output types", 81); 24 | BeaconOutput(CALLBACK_OUTPUT, "こんにちは世界", 22); 25 | BeaconOutput(CALLBACK_OUTPUT_OEM, "こんにちは世界", 22); 26 | BeaconOutput(CALLBACK_OUTPUT_UTF8, "こんにちは世界", 22); 27 | 28 | /* Examples using the CALLBACK_ERROR type */ 29 | BeaconOutput(CALLBACK_ERROR, userString, userStringLen); 30 | BeaconOutput(CALLBACK_ERROR, "hard coded error string", 23); 31 | 32 | BeaconOutput(CALLBACK_OUTPUT, "!!!! End testBeaconOutput !!!!\n\n", 32); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /tests/src/testBeaconPrintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | 5 | void go(char * args, int alen) { 6 | datap parser; 7 | char * userString; 8 | int userNum; 9 | int userStringLen = 0; 10 | 11 | /* Parse the parameters */ 12 | BeaconDataParse(&parser, args, alen); 13 | userString = BeaconDataExtract(&parser, &userStringLen); 14 | userNum = BeaconDataInt(&parser); 15 | 16 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! testBeaconPrintf !!!!"); 17 | 18 | BeaconPrintf(CALLBACK_OUTPUT, "Arguments: %s, %d", userString, userNum); 19 | BeaconPrintf(CALLBACK_OUTPUT, "Some text string with no line feed"); 20 | BeaconPrintf(CALLBACK_OUTPUT, "Another text string with a line feed\n"); 21 | 22 | /* Hello world string in Japanese, CALLBACK_OUTPUT_UTF8 is the correct ouput type */ 23 | BeaconPrintf(CALLBACK_OUTPUT, "Next three outputs represent 'Hello world' in Japanese using the 3 output types"); 24 | BeaconPrintf(CALLBACK_OUTPUT, "こんにちは世界"); 25 | BeaconPrintf(CALLBACK_OUTPUT_OEM, "こんにちは世界"); 26 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "こんにちは世界"); 27 | 28 | BeaconPrintf(CALLBACK_ERROR, "Error: %s, %d", userString, userNum); 29 | BeaconPrintf(CALLBACK_ERROR, "hard coded error string"); 30 | 31 | BeaconPrintf(CALLBACK_OUTPUT, "!!!! End testBeaconPrintf !!!!\n\n"); 32 | } 33 | 34 | --------------------------------------------------------------------------------