[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fUFpMYEFik11rPar0ijLMZC_1pkrI727IDupdCZjCuVA":3},{"id":4,"question":5,"answer":6,"answerHtml":7,"slug":8,"keywords":9,"article":10,"status":34,"aiModel":39,"aiConfidence":39,"updatedAt":51,"createdAt":51,"_status":50},1074,"Why can't we use fixed memory addresses in shellcode on modern Windows systems like Windows 7?","Modern Windows systems implement Address Space Layout Randomization (ASLR), which randomizes the base addresses of loaded modules like kernel32.dll and user32.dll. This makes hardcoded addresses unreliable for shellcode. To overcome this, shellcode must dynamically locate API addresses at runtime, as explained in this article on [Windows Shellcode Study Notes - Generating Shellcode via Visual Studio](\u002Fnews\u002Fwindows-shellcode-study-notes-generating-shellcode-via-visual-studio).","\u003Cp>Modern Windows systems implement Address Space Layout Randomization (ASLR), which randomizes the base addresses of loaded modules like kernel32.dll and user32.dll. This makes hardcoded addresses unreliable for shellcode. To overcome this, shellcode must dynamically locate API addresses at runtime, as explained in this article on [Windows Shellcode Study Notes - Generating Shellcode via Visual Studio](\u002Fnews\u002Fwindows-shellcode-study-notes-generating-shellcode-via-visual-studio).\u003C\u002Fp>\u003Cp>\u003Ca href=\"\u002Fnews\u002Fwindows-shellcode-study-notes-generating-shellcode-via-visual-studio\">Read the related One Day Sec article\u003C\u002Fa>\u003C\u002Fp>","why-cant-we-use-fixed-memory-addresses-in-shellcode-on-modern-windows-systems-li-1777480903756","ASLR, shellcode, fixed addresses, Windows 7, dynamic API resolution",{"id":11,"title":12,"slug":13,"description":14,"content":15,"contentHtml":30,"cover":31,"author":32,"views":19,"readingTime":33,"status":34,"publishedAt":35,"seo":36,"tags":41,"qaPairs":42,"meta":47,"updatedAt":48,"createdAt":49,"_status":50},262,"Windows Shellcode Study Notes - Generating Shellcode via Visual Studio","windows-shellcode-study-notes-generating-shellcode-via-visual-studio","Learn to generate Windows shellcode using Visual Studio. Methods include DEBUG mode extraction, ShellcodeCompiler tool, and C++ dynamic API calls for custom payloads.",{"root":16},{"type":17,"format":18,"indent":19,"version":20,"children":21,"direction":29},"root","",0,1,[22],{"type":23,"format":18,"indent":19,"version":20,"children":24,"direction":29},"paragraph",[25],{"mode":26,"text":27,"type":28,"style":18,"detail":19,"format":19,"version":20},"normal","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Shellcode is a piece of machine code, commonly used as the payload in vulnerability exploitation.\u003C\u002Fp>\u003Cp>In penetration testing, the simplest and most efficient method is to generate shellcode via Metasploit. However, in certain environments, custom development of one's own shellcode is required, necessitating further research into shellcode development.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>There are three basic approaches to writing Shellcode:\u003C\u002Fp>\u003Cul>\u003Cli>Directly writing hexadecimal opcodes.\u003C\u002Fli>\u003Cli>Using high-level languages like C or Delphi to write a program, compiling it, and then disassembling it to obtain hexadecimal opcodes.\u003C\u002Fli>\u003Cli>Writing an assembly program, assembling it, and extracting hexadecimal opcodes from the binary.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>This article will explain how to generate shellcode by writing C code in Visual Studio, specifically covering the following three parts:\u003C\u002Fp>\u003Cul>\u003Cli>Using the DEBUG mode of VC6.0 to obtain shellcode.\u003C\u002Fli>\u003Cli>Testing the Shellcode automatic generation tool - ShellcodeCompiler.\u003C\u002Fli>\u003Cli>Writing in C++ (without using inline assembly) to dynamically obtain API addresses and call them, and disassembling it to extract shellcode.\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Using VC6.0 DEBUG mode to obtain shellcode\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>This section references the appendix of '挖0day' by 爱无言\u003C\u002Fp>\u003Cp>\u003Cstrong>Test system:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Windows XP\u003C\u002Fp>\u003Ch3>1. Write a pop-up test program and extract assembly code\u003C\u002Fh3>\u003Cp>Code is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \"stdafx.h\"\u003Cbr>#include \u003Cwindows.h>\u003Cbr>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tMessageBoxA(NULL,NULL,NULL,0);\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Set a breakpoint at MessageBoxA(NULL,NULL,NULL,0); by pressing F9\u003C\u002Fp>\u003Cp>In debug mode, press F5 to start debugging and jump to the breakpoint\u003C\u002Fp>\u003Cp>Press Alt+8 to convert the current C code to assembly code, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770015582972_0_1ec730e0a0.png\">\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>00401028   mov         esi,esp\u003Cbr>0040102A   push        0\u003Cbr>0040102C   push        0\u003Cbr>0040102E   push        0\u003Cbr>00401030   push        0\u003Cbr>00401032   call        dword ptr [__imp__MessageBoxA@16 (0042528c)]\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>call is an indirect memory call instruction, requiring an actual memory address for practical use\u003C\u002Fp>\u003Cp>Press Alt+6 to open the Memory window for viewing memory data, jump to address 0x0042528c, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770015586759_1_5cf7111065.png\">\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>0042528C  EA 07 D5 77 00 00 00  ..誻...\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Take the first 4 bytes and reverse their order (data is stored in reverse in memory):\u003C\u002Fp>\u003Cp>77D507EA\u003C\u002Fp>\u003Cp>The actual address of the call command is 0x77D507EA\u003C\u002Fp>\u003Cp>The MessageBoxA function is located in user32.dll and requires loading user32.dll in advance when called\u003C\u002Fp>\u003Ch3>2. Write inline assembly program and extract machine code\u003C\u002Fh3>\u003Cp>Create a new project and use inline assembly to load the above code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \"stdafx.h\"\u003Cbr>#include \u003Cwindows.h>\u003Cbr>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tLoadLibrary(\"user32.dll\");\u003Cbr>\t_asm\u003Cbr>\t{\t\u003Cbr>\t\tpush        0\u003Cbr>\t\tpush        0\u003Cbr>\t\tpush        0\u003Cbr>\t\tpush        0\u003Cbr>\t\tmov eax,0x77D507EA\u003Cbr>\t\tcall eax\u003Cbr>\t}\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Compile and execute, successfully pops up a dialog box\u003C\u002Fp>\u003Cp>Set a breakpoint at push 0 by pressing F9, then press F5 to enter debug mode and jump to the breakpoint\u003C\u002Fp>\u003Cp>Press Alt+8 to convert the current VC code to assembly code, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770015588565_2_ea0a395e7d.png\">\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>12:           push        0\u003Cbr>0040103C   push        0\u003Cbr>13:           push        0\u003Cbr>0040103E   push        0\u003Cbr>14:           push        0\u003Cbr>00401040   push        0\u003Cbr>15:           push        0\u003Cbr>00401042   push        0\u003Cbr>16:           mov eax,0x77D507EA\u003Cbr>00401044   mov         eax,77D507EAh\u003Cbr>17:           call eax\u003Cbr>00401049   call        eax\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Next, extract the data of the above code in memory, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770015594012_3_514cf25e87.png\">\u003C\u002Fp>\u003Cp>The range is 0040103C - 0040104A\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The address of call eax is 00401049, indicating the starting address; the full code length needs +1\u003C\u002Fp>\u003Cp>Press Alt+6 to open the Memory window to view memory data\u003C\u002Fp>\u003Cp>Jump to 0x0040103C, the content is as follows:\u003C\u002Fp>\u003Cp>0040103C  6A 00 6A 00 6A 00 6A 00 B8 EA 07 D5 77 FF D0  j.j.j.j.戈.誻..\u003C\u002Fp>\u003Cp>The content from 0040103C - 0040104A is as follows:\u003C\u002Fp>\u003Cp>6A 00 6A 00 6A 00 6A 00 B8 EA 07 D5 77 FF D0\u003C\u002Fp>\u003Cp>This machine code is the shellcode to be used next.\u003C\u002Fp>\u003Ch3>3. Write a test program to load the shellcode\u003C\u002Fh3>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \"stdafx.h\"\u003Cbr>#include \u003Cwindows.h>\u003Cbr>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tLoadLibrary(\"user32.dll\");\u003Cbr>\tchar shellcode[]=\"\\x6A\\x00\\x6A\\x00\\x6A\\x00\\x6A\\x00\\xB8\\xEA\\x07\\xD5\\x77\\xFF\\xD0\";\u003Cbr>\t((void(*)(void))&amp;shellcode)();\u003Cbr>\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Shellcode executed successfully\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Due to the introduction of the ASLR mechanism in Windows 7, we cannot use fixed memory addresses in shellcode, making the above method not universally applicable under Windows 7.\u003C\u002Fp>\u003Ch2>0x03 Shellcode Automatic Generation Tool—ShellcodeCompiler\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>\u003Cstrong>Download Link:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002FNytroRST\u002FShellcodeCompiler\u003C\u002Fp>\u003Cp>\u003Cstrong>Features:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>Developed in C++\u003C\u002Fli>\u003Cli>Open-source tool\u003C\u002Fli>\u003Cli>Utilizes NASM\u003C\u002Fli>\u003Cli>Can encapsulate APIs and convert them into shellcode in bin format and ASM assembly code\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Actual Test:\u003C\u002Fp>\u003Cp>The content of Source.txt is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function MessageBoxA(\"user32.dll\");\u003Cbr>function ExitProcess(\"kernel32.dll\");\u003Cbr>MessageBoxA(0,\"This is a MessageBox example\",\"Shellcode Compiler\",0);\u003Cbr>ExitProcess(0);\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Run in cmd:\u003C\u002Fp>\u003Cp>ShellcodeCompiler.exe -r Source.txt -o Shellcode.bin -a Assembly.asm\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Place ShellcodeCompiler.exe and the NASM folder in the same directory\u003C\u002Fp>\u003Cp>After execution, the shellcode is saved in the Shellcode.bin file\u003C\u002Fp>\u003Cp>To facilitate testing of the generated shellcode, add the -t parameter during generation to execute the shellcode once\u003C\u002Fp>\u003Cp>I referenced the code of ShellcodeCompiler to extract its shellcode execution functionality, implementing reading a file and loading the shellcode from it. The complete code is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \u003Cwindows.h>\u003Cbr>\u003Cbr>size_t GetSize(char * szFilePath)\u003Cbr>{\u003Cbr>\tsize_t size;\u003Cbr>\tFILE* f = fopen(szFilePath, \"rb\");\u003Cbr>\tfseek(f, 0, SEEK_END);\u003Cbr>\tsize = ftell(f);\u003Cbr>\trewind(f);\u003Cbr>\tfclose(f);\u003Cbr>\treturn size;\u003Cbr>}\u003Cbr>\u003Cbr>unsigned char* ReadBinaryFile(char *szFilePath, size_t *size)\u003Cbr>{\u003Cbr>\tunsigned char *p = NULL;\u003Cbr>\tFILE* f = NULL;\u003Cbr>\tsize_t res = 0;\u003Cbr>\t\u002F\u002F Get size and allocate space\u003Cbr>\t*size = GetSize(szFilePath);\u003Cbr>\tif (*size == 0) return NULL;\t\t\u003Cbr>\tf = fopen(szFilePath, \"rb\");\u003Cbr>\tif (f == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"Binary file does not exists!\\n\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\tp = new unsigned char[*size];\u003Cbr>\t\u002F\u002F Read file\u003Cbr>\trewind(f);\u003Cbr>\tres = fread(p, sizeof(unsigned char), *size, f);\u003Cbr>\tfclose(f);\u003Cbr>\tif (res == 0)\u003Cbr>\t{\u003Cbr>\t\tdelete[] p;\u003Cbr>\t\treturn NULL;\u003Cbr>\t}\u003Cbr>\treturn p;\u003Cbr>}\u003Cbr>\u003Cbr>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tchar *szFilePath=argv[1];\u003Cbr>\tunsigned char *BinData = NULL;\u003Cbr>\tsize_t size = 0;\u003Cbr>\tBinData = ReadBinaryFile(szFilePath, &amp;size);\u003Cbr>\tvoid *sc = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);\u003Cbr>\tif (sc == NULL)\u003Cbr>\t{\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\tmemcpy(sc, BinData, size);\u003Cbr>\t(*(int(*)()) sc)();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x04 Written in C++ (without using inline assembly), implements dynamic retrieval of API addresses and calls, from which shellcode can be extracted by disassembly.\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>For ShellcodeCompiler, the biggest drawback is the use of inline assembly; VC does not support inline assembly by default in 64-bit, so this method cannot generate 64-bit shellcode.\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Delphi supports inline assembly in 64-bit.\u003C\u002Fp>\u003Cp>Although VC cannot directly use inline assembly in 64-bit, program segments can be placed entirely in an asm file for compilation.\u003C\u002Fp>\u003Cp>For methods to restore the VS keyword __asm on X64, refer to:\u003C\u002Fp>\u003Cp>http:\u002F\u002Fbbs.pediy.com\u002Fshowthread.php?p=1260419\u003C\u002Fp>\u003Cp>Therefore, the most direct way to develop a 64-bit shellcode is to avoid inline assembly, write purely in C++, implement dynamic retrieval of API addresses and calls, and then disassemble it to obtain shellcode.\u003C\u002Fp>\u003Cp>\u003Cstrong>The benefits are as follows:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Facilitates debugging, greatly enhancing the readability of the source code.\u003C\u002Fp>\u003Cp>However, I did not find ready-made code online, so I attempted to implement it myself based on the principles.\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>1. Writing shellcode requires implementing the following steps:\u003C\u002Fp>\u003Cul>\u003Cli>Retrieve the base address of kernel32.dll.\u003C\u002Fli>\u003Cli>Locate the address of the GetProcAddress function\u003C\u002Fli>\u003Cli>Use GetProcAddress to determine the address of the LoadLibrary function\u003C\u002Fli>\u003Cli>Use LoadLibrary to load a DLL file\u003C\u002Fli>\u003Cli>Use GetProcAddress to find the address of a specific function (e.g., MessageBox)\u003C\u002Fli>\u003Cli>Specify function parameters\u003C\u002Fli>\u003Cli>Call the function\u003C\u002Fli>\u003C\u002Ful>\u003Cp>2. Another reference material:\u003C\u002Fp>\u003Cp>http:\u002F\u002Fbbs.pediy.com\u002Fshowthread.php?t=203140\u003C\u002Fp>\u003Cp>The reference material implements loading a third-party DLL using C++\u003C\u002Fp>\u003Cp>Modify based on this reference to achieve our desired functionality:\u003C\u002Fp>\u003Cp>Implement dynamic retrieval of API addresses and calls\u003C\u002Fp>\u003Cp>The complete code has been uploaded to GitHub:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>\u003Cstrong>Features:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>Supports x86 and x64\u003C\u002Fli>\u003Cli>Pure C++ implementation, dynamically obtaining the addresses of GetProcAddress and LoadLibrary functions.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Before compilation, configure Visual Studio as follows:\u003C\u002Fp>\u003Cp>1. Use Release mode. Recent compilers' Debug mode may produce reversed functions and insert many position-dependent calls.\u003C\u002Fp>\u003Cp>2. Disable optimization. The compiler optimizes unused functions by default, which may be exactly what we need.\u003C\u002Fp>\u003Cp>3. Disable stack buffer security checks (\u002FGs). The stack check functions called at the beginning and end of functions exist at specific locations in the binary file, causing the output functions to be non-relocatable, which is meaningless for shellcode.\u003C\u002Fp>\u003Cp>Then open the generated exe in IDA to obtain the machine code.\u003C\u002Fp>\u003Ch2>0.05 Supplement\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Next research topics:\u003C\u002Fp>\u003Cul>\u003Cli>After restoring the VS keyword __asm on X64, how to obtain 64-bit shellcode.\u003C\u002Fli>\u003C\u002Ful>\u003C\u002Fbody>\u003C\u002Fhtml>","text","ltr","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Shellcode is a piece of machine code, commonly used as the payload in vulnerability exploitation.\u003C\u002Fp>\u003Cp>In penetration testing, the simplest and most efficient method is to generate shellcode via Metasploit. However, in certain environments, custom development of one's own shellcode is required, necessitating further research into shellcode development.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>There are three basic approaches to writing Shellcode:\u003C\u002Fp>\u003Cul>\u003Cli>Directly writing hexadecimal opcodes.\u003C\u002Fli>\u003Cli>Using high-level languages like C or Delphi to write a program, compiling it, and then disassembling it to obtain hexadecimal opcodes.\u003C\u002Fli>\u003Cli>Writing an assembly program, assembling it, and extracting hexadecimal opcodes from the binary.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>This article will explain how to generate shellcode by writing C code in Visual Studio, specifically covering the following three parts:\u003C\u002Fp>\u003Cul>\u003Cli>Using the DEBUG mode of VC6.0 to obtain shellcode.\u003C\u002Fli>\u003Cli>Testing the Shellcode automatic generation tool - ShellcodeCompiler.\u003C\u002Fli>\u003Cli>Writing in C++ (without using inline assembly) to dynamically obtain API addresses and call them, and disassembling it to extract shellcode.\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Using VC6.0 DEBUG mode to obtain shellcode\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>This section references the appendix of '挖0day' by 爱无言\u003C\u002Fp>\u003Cp>\u003Cstrong>Test system:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Windows XP\u003C\u002Fp>\u003Ch3>1. Write a pop-up test program and extract assembly code\u003C\u002Fh3>\u003Cp>Code is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \"stdafx.h\"\u003Cbr>#include \u003Cwindows.h>\u003Cbr>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tMessageBoxA(NULL,NULL,NULL,0);\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Set a breakpoint at MessageBoxA(NULL,NULL,NULL,0); by pressing F9\u003C\u002Fp>\u003Cp>In debug mode, press F5 to start debugging and jump to the breakpoint\u003C\u002Fp>\u003Cp>Press Alt+8 to convert the current C code to assembly code, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770015582972_0_1ec730e0a0-1.png\">\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>00401028   mov         esi,esp\u003Cbr>0040102A   push        0\u003Cbr>0040102C   push        0\u003Cbr>0040102E   push        0\u003Cbr>00401030   push        0\u003Cbr>00401032   call        dword ptr [__imp__MessageBoxA@16 (0042528c)]\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>call is an indirect memory call instruction, requiring an actual memory address for practical use\u003C\u002Fp>\u003Cp>Press Alt+6 to open the Memory window for viewing memory data, jump to address 0x0042528c, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770015586759_1_5cf7111065-1.png\">\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>0042528C  EA 07 D5 77 00 00 00  ..誻...\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Take the first 4 bytes and reverse their order (data is stored in reverse in memory):\u003C\u002Fp>\u003Cp>77D507EA\u003C\u002Fp>\u003Cp>The actual address of the call command is 0x77D507EA\u003C\u002Fp>\u003Cp>The MessageBoxA function is located in user32.dll and requires loading user32.dll in advance when called\u003C\u002Fp>\u003Ch3>2. Write inline assembly program and extract machine code\u003C\u002Fh3>\u003Cp>Create a new project and use inline assembly to load the above code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \"stdafx.h\"\u003Cbr>#include \u003Cwindows.h>\u003Cbr>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tLoadLibrary(\"user32.dll\");\u003Cbr>\t_asm\u003Cbr>\t{\t\u003Cbr>\t\tpush        0\u003Cbr>\t\tpush        0\u003Cbr>\t\tpush        0\u003Cbr>\t\tpush        0\u003Cbr>\t\tmov eax,0x77D507EA\u003Cbr>\t\tcall eax\u003Cbr>\t}\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Compile and execute, successfully pops up a dialog box\u003C\u002Fp>\u003Cp>Set a breakpoint at push 0 by pressing F9, then press F5 to enter debug mode and jump to the breakpoint\u003C\u002Fp>\u003Cp>Press Alt+8 to convert the current VC code to assembly code, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770015588565_2_ea0a395e7d-1.png\">\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>12:           push        0\u003Cbr>0040103C   push        0\u003Cbr>13:           push        0\u003Cbr>0040103E   push        0\u003Cbr>14:           push        0\u003Cbr>00401040   push        0\u003Cbr>15:           push        0\u003Cbr>00401042   push        0\u003Cbr>16:           mov eax,0x77D507EA\u003Cbr>00401044   mov         eax,77D507EAh\u003Cbr>17:           call eax\u003Cbr>00401049   call        eax\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Next, extract the data of the above code in memory, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770015594012_3_514cf25e87-1.png\">\u003C\u002Fp>\u003Cp>The range is 0040103C - 0040104A\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The address of call eax is 00401049, indicating the starting address; the full code length needs +1\u003C\u002Fp>\u003Cp>Press Alt+6 to open the Memory window to view memory data\u003C\u002Fp>\u003Cp>Jump to 0x0040103C, the content is as follows:\u003C\u002Fp>\u003Cp>0040103C  6A 00 6A 00 6A 00 6A 00 B8 EA 07 D5 77 FF D0  j.j.j.j.戈.誻..\u003C\u002Fp>\u003Cp>The content from 0040103C - 0040104A is as follows:\u003C\u002Fp>\u003Cp>6A 00 6A 00 6A 00 6A 00 B8 EA 07 D5 77 FF D0\u003C\u002Fp>\u003Cp>This machine code is the shellcode to be used next.\u003C\u002Fp>\u003Ch3>3. Write a test program to load the shellcode\u003C\u002Fh3>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \"stdafx.h\"\u003Cbr>#include \u003Cwindows.h>\u003Cbr>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tLoadLibrary(\"user32.dll\");\u003Cbr>\tchar shellcode[]=\"\\x6A\\x00\\x6A\\x00\\x6A\\x00\\x6A\\x00\\xB8\\xEA\\x07\\xD5\\x77\\xFF\\xD0\";\u003Cbr>\t((void(*)(void))&amp;shellcode)();\u003Cbr>\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Shellcode executed successfully\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Due to the introduction of the ASLR mechanism in Windows 7, we cannot use fixed memory addresses in shellcode, making the above method not universally applicable under Windows 7.\u003C\u002Fp>\u003Ch2>0x03 Shellcode Automatic Generation Tool—ShellcodeCompiler\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>\u003Cstrong>Download Link:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002FNytroRST\u002FShellcodeCompiler\u003C\u002Fp>\u003Cp>\u003Cstrong>Features:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>Developed in C++\u003C\u002Fli>\u003Cli>Open-source tool\u003C\u002Fli>\u003Cli>Utilizes NASM\u003C\u002Fli>\u003Cli>Can encapsulate APIs and convert them into shellcode in bin format and ASM assembly code\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Actual Test:\u003C\u002Fp>\u003Cp>The content of Source.txt is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function MessageBoxA(\"user32.dll\");\u003Cbr>function ExitProcess(\"kernel32.dll\");\u003Cbr>MessageBoxA(0,\"This is a MessageBox example\",\"Shellcode Compiler\",0);\u003Cbr>ExitProcess(0);\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Run in cmd:\u003C\u002Fp>\u003Cp>ShellcodeCompiler.exe -r Source.txt -o Shellcode.bin -a Assembly.asm\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Place ShellcodeCompiler.exe and the NASM folder in the same directory\u003C\u002Fp>\u003Cp>After execution, the shellcode is saved in the Shellcode.bin file\u003C\u002Fp>\u003Cp>To facilitate testing of the generated shellcode, add the -t parameter during generation to execute the shellcode once\u003C\u002Fp>\u003Cp>I referenced the code of ShellcodeCompiler to extract its shellcode execution functionality, implementing reading a file and loading the shellcode from it. The complete code is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \u003Cwindows.h>\u003Cbr>\u003Cbr>size_t GetSize(char * szFilePath)\u003Cbr>{\u003Cbr>\tsize_t size;\u003Cbr>\tFILE* f = fopen(szFilePath, \"rb\");\u003Cbr>\tfseek(f, 0, SEEK_END);\u003Cbr>\tsize = ftell(f);\u003Cbr>\trewind(f);\u003Cbr>\tfclose(f);\u003Cbr>\treturn size;\u003Cbr>}\u003Cbr>\u003Cbr>unsigned char* ReadBinaryFile(char *szFilePath, size_t *size)\u003Cbr>{\u003Cbr>\tunsigned char *p = NULL;\u003Cbr>\tFILE* f = NULL;\u003Cbr>\tsize_t res = 0;\u003Cbr>\t\u002F\u002F Get size and allocate space\u003Cbr>\t*size = GetSize(szFilePath);\u003Cbr>\tif (*size == 0) return NULL;\t\t\u003Cbr>\tf = fopen(szFilePath, \"rb\");\u003Cbr>\tif (f == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"Binary file does not exists!\\n\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\tp = new unsigned char[*size];\u003Cbr>\t\u002F\u002F Read file\u003Cbr>\trewind(f);\u003Cbr>\tres = fread(p, sizeof(unsigned char), *size, f);\u003Cbr>\tfclose(f);\u003Cbr>\tif (res == 0)\u003Cbr>\t{\u003Cbr>\t\tdelete[] p;\u003Cbr>\t\treturn NULL;\u003Cbr>\t}\u003Cbr>\treturn p;\u003Cbr>}\u003Cbr>\u003Cbr>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tchar *szFilePath=argv[1];\u003Cbr>\tunsigned char *BinData = NULL;\u003Cbr>\tsize_t size = 0;\u003Cbr>\tBinData = ReadBinaryFile(szFilePath, &amp;size);\u003Cbr>\tvoid *sc = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);\u003Cbr>\tif (sc == NULL)\u003Cbr>\t{\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\tmemcpy(sc, BinData, size);\u003Cbr>\t(*(int(*)()) sc)();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x04 Written in C++ (without using inline assembly), implements dynamic retrieval of API addresses and calls, from which shellcode can be extracted by disassembly.\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>For ShellcodeCompiler, the biggest drawback is the use of inline assembly; VC does not support inline assembly by default in 64-bit, so this method cannot generate 64-bit shellcode.\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Delphi supports inline assembly in 64-bit.\u003C\u002Fp>\u003Cp>Although VC cannot directly use inline assembly in 64-bit, program segments can be placed entirely in an asm file for compilation.\u003C\u002Fp>\u003Cp>For methods to restore the VS keyword __asm on X64, refer to:\u003C\u002Fp>\u003Cp>http:\u002F\u002Fbbs.pediy.com\u002Fshowthread.php?p=1260419\u003C\u002Fp>\u003Cp>Therefore, the most direct way to develop a 64-bit shellcode is to avoid inline assembly, write purely in C++, implement dynamic retrieval of API addresses and calls, and then disassemble it to obtain shellcode.\u003C\u002Fp>\u003Cp>\u003Cstrong>The benefits are as follows:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Facilitates debugging, greatly enhancing the readability of the source code.\u003C\u002Fp>\u003Cp>However, I did not find ready-made code online, so I attempted to implement it myself based on the principles.\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>1. Writing shellcode requires implementing the following steps:\u003C\u002Fp>\u003Cul>\u003Cli>Retrieve the base address of kernel32.dll.\u003C\u002Fli>\u003Cli>Locate the address of the GetProcAddress function\u003C\u002Fli>\u003Cli>Use GetProcAddress to determine the address of the LoadLibrary function\u003C\u002Fli>\u003Cli>Use LoadLibrary to load a DLL file\u003C\u002Fli>\u003Cli>Use GetProcAddress to find the address of a specific function (e.g., MessageBox)\u003C\u002Fli>\u003Cli>Specify function parameters\u003C\u002Fli>\u003Cli>Call the function\u003C\u002Fli>\u003C\u002Ful>\u003Cp>2. Another reference material:\u003C\u002Fp>\u003Cp>http:\u002F\u002Fbbs.pediy.com\u002Fshowthread.php?t=203140\u003C\u002Fp>\u003Cp>The reference material implements loading a third-party DLL using C++\u003C\u002Fp>\u003Cp>Modify based on this reference to achieve our desired functionality:\u003C\u002Fp>\u003Cp>Implement dynamic retrieval of API addresses and calls\u003C\u002Fp>\u003Cp>The complete code has been uploaded to GitHub:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>\u003Cstrong>Features:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>Supports x86 and x64\u003C\u002Fli>\u003Cli>Pure C++ implementation, dynamically obtaining the addresses of GetProcAddress and LoadLibrary functions.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Before compilation, configure Visual Studio as follows:\u003C\u002Fp>\u003Cp>1. Use Release mode. Recent compilers' Debug mode may produce reversed functions and insert many position-dependent calls.\u003C\u002Fp>\u003Cp>2. Disable optimization. The compiler optimizes unused functions by default, which may be exactly what we need.\u003C\u002Fp>\u003Cp>3. Disable stack buffer security checks (\u002FGs). The stack check functions called at the beginning and end of functions exist at specific locations in the binary file, causing the output functions to be non-relocatable, which is meaningless for shellcode.\u003C\u002Fp>\u003Cp>Then open the generated exe in IDA to obtain the machine code.\u003C\u002Fp>\u003Ch2>0.05 Supplement\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Next research topics:\u003C\u002Fp>\u003Cul>\u003Cli>After restoring the VS keyword __asm on X64, how to obtain 64-bit shellcode.\u003C\u002Fli>\u003C\u002Ful>\u003C\u002Fbody>\u003C\u002Fhtml>",285,"Onedaysec",6,"published","2026-02-02T07:25:19.985Z",{"title":37,"description":14,"keywords":38,"ogImage":39,"canonicalUrl":39,"noIndex":40},"Generate Shellcode via Visual Studio: Windows Shellcode Study Notes","shellcode generation, Visual Studio, Windows shellcode, C++ shellcode, assembly code, penetration testing, vulnerability exploitation, machine code, API calls, inline assembly",null,false,[],{"docs":43,"hasNextPage":40},[44,45,46,4],1077,1076,1075,{"title":39,"description":39,"image":39},"2026-07-24T15:37:09.823Z","2026-07-23T16:02:29.682Z","draft","2026-07-23T16:16:29.570Z"]