⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pe-tut6.html

📁 在DOS下编程因为实模式的限制
💻 HTML
📖 第 1 页 / 共 4 页
字号:
            invoke MessageBox, 0, 
  addr FileMappingError, addr AppName, MB_OK+MB_ICONERROR <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.endif <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke CloseHandle,hMapping <br>
  &nbsp;&nbsp;&nbsp;&nbsp;.else <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke MessageBox, 0, addr FileOpenMappingError, 
  addr AppName, MB_OK+MB_ICONERROR <br>
  &nbsp;&nbsp;&nbsp; .endif <br>
  &nbsp;&nbsp;&nbsp; invoke CloseHandle, hFile <br>
  &nbsp;&nbsp; .else <br>
  &nbsp;&nbsp;&nbsp;invoke MessageBox, 0, addr FileOpenError, addr AppName, MB_OK+MB_ICONERROR 
  <br>
  &nbsp;&nbsp; .endif <br>
  &nbsp;.endif <br>
  &nbsp;ret <br>
  ShowImportFunctions endp <br>
  <br>
  AppendText proc hDlg:DWORD,pText:DWORD <br>
  &nbsp;&nbsp; invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_REPLACESEL,0,pText <br>
  &nbsp;&nbsp; invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_REPLACESEL,0,addr CRLF 
  <br>
  &nbsp;&nbsp; invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_SETSEL,-1,0 <br>
  &nbsp;&nbsp;&nbsp;ret <br>
  AppendText endp <br>
  <br>
  RVAToOffset PROC uses edi esi edx ecx pFileMap:DWORD,RVA:DWORD <br>
  &nbsp;&nbsp; mov esi,pFileMap <br>
  &nbsp;&nbsp; assume esi:ptr IMAGE_DOS_HEADER <br>
  &nbsp;&nbsp; add esi,[esi].e_lfanew <br>
  &nbsp;&nbsp; assume esi:ptr IMAGE_NT_HEADERS <br>
  &nbsp;&nbsp; mov edi,RVA ; edi == RVA <br>
  &nbsp;&nbsp; mov edx,esi <br>
  &nbsp;&nbsp; add edx,sizeof IMAGE_NT_HEADERS <br>
  &nbsp;&nbsp; mov cx,[esi].FileHeader.NumberOfSections <br>
  &nbsp;&nbsp; movzx ecx,cx <br>
  &nbsp;&nbsp; assume edx:ptr IMAGE_SECTION_HEADER <br>
  &nbsp;&nbsp; .while ecx>0 ; check all sections <br>
  &nbsp;&nbsp;&nbsp;&nbsp; .if edi>=[edx].VirtualAddress <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax,[edx].VirtualAddress <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add eax,[edx].SizeOfRawData <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .if edi&lt;eax ; The address is in this 
  section <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov eax,[edx].VirtualAddress 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sub edi,eax<br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax,[edx].PointerToRawData 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add eax,edi ; eax == file offset 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .endif <br>
  &nbsp;&nbsp;&nbsp;&nbsp; .endif <br>
  &nbsp;&nbsp;&nbsp;&nbsp; add edx,sizeof IMAGE_SECTION_HEADER <br>
  &nbsp;&nbsp;&nbsp;&nbsp; dec ecx <br>
  &nbsp;&nbsp; .endw <br>
  &nbsp;&nbsp; assume edx:nothing <br>
  &nbsp;&nbsp; assume esi:nothing <br>
  &nbsp;&nbsp; mov eax,edi <br>
  &nbsp;&nbsp; ret <br>
  RVAToOffset endp <br>
  <br>
  ShowTheFunctions proc uses esi ecx ebx hDlg:DWORD, pNTHdr:DWORD <br>
  &nbsp;&nbsp; LOCAL temp[512]:BYTE <br>
  &nbsp;&nbsp; invoke SetDlgItemText,hDlg,IDC_EDIT,0 <br>
  &nbsp;&nbsp; invoke AppendText,hDlg,addr buffer <br>
  &nbsp;&nbsp; mov edi,pNTHdr <br>
  &nbsp;&nbsp; assume edi:ptr IMAGE_NT_HEADERS <br>
  &nbsp;&nbsp; mov edi, [edi].OptionalHeader.DataDirectory[sizeof IMAGE_DATA_DIRECTORY].VirtualAddress 
  <br>
  &nbsp;&nbsp; invoke RVAToOffset,pMapping,edi <br>
  &nbsp;&nbsp; mov edi,eax <br>
  &nbsp;&nbsp; add edi,pMapping <br>
  &nbsp;&nbsp; assume edi:ptr IMAGE_IMPORT_DESCRIPTOR <br>
  &nbsp;&nbsp; .while !([edi].OriginalFirstThunk==0 && [edi].TimeDateStamp==0 
  && [edi].ForwarderChain==0 && [edi].Name1==0 && [edi].FirstThunk==0) <br>
  &nbsp;&nbsp;&nbsp;&nbsp; invoke AppendText,hDlg,addr ImportDescriptor <br>
  &nbsp;&nbsp;&nbsp;&nbsp; invoke RVAToOffset,pMapping, [edi].Name1 <br>
  &nbsp;&nbsp;&nbsp;&nbsp; mov edx,eax <br>
  &nbsp;&nbsp;&nbsp;&nbsp; add edx,pMapping <br>
  &nbsp;&nbsp;&nbsp;&nbsp; invoke wsprintf, addr temp, addr IDTemplate, [edi].OriginalFirstThunk,[edi].TimeDateStamp,[edi].ForwarderChain,edx,[edi].FirstThunk 
  &nbsp;&nbsp;&nbsp;&nbsp; invoke AppendText,hDlg,addr temp <br>
  &nbsp;&nbsp;&nbsp;&nbsp; .if [edi].OriginalFirstThunk==0 <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov esi,[edi].FirstThunk <br>
  &nbsp;&nbsp;&nbsp;&nbsp; .else <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov esi,[edi].OriginalFirstThunk 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp; .endif <br>
  &nbsp;&nbsp;&nbsp;&nbsp; invoke RVAToOffset,pMapping,esi <br>
  &nbsp;&nbsp;&nbsp;&nbsp; add eax,pMapping <br>
  &nbsp;&nbsp;&nbsp;&nbsp; mov esi,eax <br>
  &nbsp;&nbsp;&nbsp;&nbsp; invoke AppendText,hDlg,addr NameHeader <br>
  &nbsp;&nbsp;&nbsp;&nbsp; .while dword ptr [esi]!=0 <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test dword ptr [esi],IMAGE_ORDINAL_FLAG32 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jnz ImportByOrdinal <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke RVAToOffset,pMapping,dword ptr [esi] 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov edx,eax <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add edx,pMapping <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assume edx:ptr IMAGE_IMPORT_BY_NAME <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov cx, [edx].Hint <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movzx ecx,cx <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke wsprintf,addr temp,addr NameTemplate,ecx,addr 
  [edx].Name1 <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jmp ShowTheText <br>
  ImportByOrdinal: <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov edx,dword ptr [esi] <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and edx,0FFFFh <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke wsprintf,addr temp,addr OrdinalTemplate,edx 
  <br>
  ShowTheText: <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke AppendText,hDlg,addr temp <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add esi,4 <br>
  &nbsp;&nbsp;&nbsp; .endw <br>
  &nbsp;&nbsp;&nbsp; add edi,sizeof IMAGE_IMPORT_DESCRIPTOR <br>
  &nbsp; .endw <br>
  &nbsp;&nbsp;ret <br>
  ShowTheFunctions endp <br>
  end start </font></p>
<h3><font face="Arial, Helvetica, sans-serif">Analysis:</font></h3>
<p><font face="MS Sans Serif" size="-1">The program shows an open file dialog 
  box when the user clicks Open in the menu. It verifies that the file is a valid 
  PE and then calls <font color="#CC9900"><b>ShowTheFunctions</b></font>.</font></p>
<p><font face="Fixedsys">ShowTheFunctions proc uses esi ecx ebx hDlg:DWORD, pNTHdr:DWORD 
  <br>
  &nbsp;&nbsp; LOCAL temp[512]:BYTE </font></p>
<p><font face="MS Sans Serif" size="-1">Reserve 512 bytes of stack space for string 
  operation.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp; invoke SetDlgItemText,hDlg,IDC_EDIT,0 </font></p>
<p><font face="MS Sans Serif" size="-1">Clear the text in the edit control</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp; invoke AppendText,hDlg,addr buffer </font></p>
<p><font face="MS Sans Serif" size="-1">Insert the name of the PE file into the 
  edit control. <font color="#CC9900"><b>AppendText </b></font>just sends <font color="#CCFFCC"><b>EM_REPLACESEL 
  </b></font> messages to append the text to the edit control. Note that it sends 
  <font color="#CCFFCC"> <b>EM_SETSEL</b></font> with wParam=-1 and lParam=0 to 
  the edit control to move the cursor to the end of the text.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp; mov edi,pNTHdr <br>
  &nbsp;&nbsp; assume edi:ptr IMAGE_NT_HEADERS <br>
  &nbsp;&nbsp; mov edi, [edi].OptionalHeader.DataDirectory[sizeof IMAGE_DATA_DIRECTORY].VirtualAddress 
  </font></p>
<p><font face="MS Sans Serif" size="-1">Obtain the RVA of the import symbols. 
  edi at first points to the PE header. We use it to go to the 2nd member of the 
  data directory array and obtain the value of VirtualAddress member.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp; invoke RVAToOffset,pMapping,edi <br>
  &nbsp;&nbsp; mov edi,eax <br>
  &nbsp;&nbsp; add edi,pMapping </font></p>
<p><font face="MS Sans Serif" size="-1">Here comes one of the pitfalls for newcomers 
  to PE programming. Most of the addresses in the PE file are RVAs and <font color="#FF6666"><b>RVAs 
  are meaningful only when the PE file is loaded into memory by the PE loader</b></font>. 
  In our case, we do map the file into memory but not the way the PE loader does. 
  Thus we cannot use those RVAs directly. Somehow we have to convert those RVAs 
  into file offsets. I write RVAToOffset function just for this purpose. I won't 
  analyze it in detail here. Suffice to say that it checks the submitted RVA against 
  the starting-ending RVAs of all sections in the PE file and use the value in 
  <font color="#FFFFCC"> <b>PointerToRawData</b></font> field in the <font color="#CCFFCC"><b>IMAGE_SECTION_HEADER</b></font> 
  structure to convert the RVA to file offset.<br>
  To use this function, you pass it two parameters: the pointer to the memory 
  mapped file and the RVA you want to convert. It returns the file offset in eax. 
  In the above snippet, we must add the pointer to the memory mapped file to the 
  file offset to convert it to virtual address. Seems complicated, huh? :)</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp; assume edi:ptr IMAGE_IMPORT_DESCRIPTOR 
  <br>
  &nbsp;&nbsp; .while !([edi].OriginalFirstThunk==0 && [edi].TimeDateStamp==0 
  && [edi].ForwarderChain==0 && [edi].Name1==0 && [edi].FirstThunk==0) </font></p>
<p><font face="MS Sans Serif" size="-1">edi now points to the first <font color="#CCFFCC"><b>IMAGE_IMPORT_DESCRIPTOR</b></font> 
  structure. We will walk the array until we find the structure with zeroes in 
  all members which denotes the end of the array.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp;&nbsp; invoke AppendText,hDlg,addr 
  ImportDescriptor<br>
  </font><font face="Fixedsys">&nbsp;&nbsp;&nbsp;&nbsp; invoke RVAToOffset,pMapping, 
  [edi].Name1 <br>
  &nbsp;&nbsp;&nbsp;&nbsp; mov edx,eax <br>
  &nbsp;&nbsp;&nbsp;&nbsp; add edx,pMapping </font></p>
<p><font face="MS Sans Serif" size="-1">We want to display the values of the current 
  <font color="#CCFFCC"> <b>IMAGE_IMPORT_DESCRIPTOR</b></font> structure in the 
  edit control. Name1 is different from the other members since it contains the 
  RVA to the name of the dll. Thus we must convert it to a virtual address first.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp;&nbsp; invoke wsprintf, addr temp, 
  addr IDTemplate, [edi].OriginalFirstThunk,[edi].TimeDateStamp,[edi].ForwarderChain,edx,[edi].FirstThunk 
  &nbsp;&nbsp;&nbsp;&nbsp; invoke AppendText,hDlg,addr temp </font></p>
<p><font face="MS Sans Serif" size="-1">Display the values of the current <font color="#CCFFCC"><b>IMAGE_IMPORT_DESCRIPTOR</b></font>.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp;&nbsp; .if [edi].OriginalFirstThunk==0 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov esi,[edi].FirstThunk <br>
  &nbsp;&nbsp;&nbsp;&nbsp; .else <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov esi,[edi].OriginalFirstThunk 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp; .endif </font></p>
<p><font face="MS Sans Serif" size="-1">Next we prepare to walk the <font color="#CCFFCC"><b>IMAGE_THUNK_DATA</b></font> 
  array. Normally we would choose to use the array pointed to by <font color="#FFFFCC"><b>OriginalFirstThunk</b></font>. 
  However, some linkers errornously put 0 in <font color="#FFFFCC"><b>OriginalFirstThunk</b></font> 
  thus we must check first if the value of <font color="#FFFFCC"><b>OriginalFirstThunk</b></font> 
  is zero. If it is, we use the array pointed to by <font color="#FFFFCC"><b>FirstThunk</b></font> 
  instead.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp;&nbsp; invoke RVAToOffset,pMapping,esi 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp; add eax,pMapping <br>
  &nbsp;&nbsp;&nbsp;&nbsp; mov esi,eax </font></p>
<p><font face="MS Sans Serif" size="-1">Again, the value in <font color="#FFFFCC"><b>OriginalFirstThunk</b></font>/<font color="#FFFFCC"><b>FirstThunk</b></font> 
  is an RVA. We must convert it to virtual address.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp;&nbsp; invoke AppendText,hDlg,addr 
  NameHeader</font><font face="Fixedsys"><br>
  &nbsp;&nbsp;&nbsp;&nbsp; .while dword ptr [esi]!=0 </font></p>
<p><font face="MS Sans Serif" size="-1">Now we are ready to walk the array of<font color="#CCFFCC"><b> 
  IMAGE_THUNK_DATAs</b></font> to look for the names of the functions imported 
  from this DLL. We will walk the array until we find an entry which contains 
  0.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test dword ptr 
  [esi],IMAGE_ORDINAL_FLAG32 <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jnz ImportByOrdinal </font></p>
<p><font face="MS Sans Serif" size="-1">The first thing we do with the<font color="#CCFFCC"><b> 
  IMAGE_THUNK_DATA</b></font> is to test it against <font color="#CCFFCC"><b>IMAGE_ORDINAL_FLAG32</b></font>. 
  This test checks if the most significant bit of the<font color="#CCFFCC"><b> 
  IMAGE_THUNK_DATA</b></font> is 1. If it is, the function is exported by ordinal 
  so we have no need to process it further. We can extract its ordinal from the 
  low word of the <font color="#CCFFCC"><b>IMAGE_THUNK_DATA</b></font> and go 
  on with the next <font color="#CCFFCC"><b>IMAGE_THUNK_DATA</b></font> dword.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke RVAToOffset,pMapping,dword 
  ptr [esi] <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov edx,eax <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add edx,pMapping <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assume edx:ptr IMAGE_IMPORT_BY_NAME </font></p>
<p><font face="MS Sans Serif" size="-1">If the MSB of the IAMGE_THUNK_DATA is 
  0, it contains the RVA of IMAGE_IMPORT_BY_NAME structure. We need to convert 
  it to virtual address first.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov cx, [edx].Hint 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movzx ecx,cx <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke wsprintf,addr temp,addr NameTemplate,ecx,addr 
  [edx].Name1 <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jmp ShowTheText </font></p>
<p><font face="MS Sans Serif" size="-1">Hint is a word-sized field. We must convert 
  it to a dword-sized value before submitting it to wsprintf. And we print both 
  the hint and the function name in the edit control</font></p>
<p><font face="Fixedsys"> ImportByOrdinal: <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov edx,dword ptr [esi] <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and edx,0FFFFh <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke wsprintf,addr temp,addr OrdinalTemplate,edx 
  </font></p>
<p><font face="MS Sans Serif" size="-1">In the case the function is exported by 
  ordinal only, we zero out the high word and display the ordinal.</font></p>
<p><font face="Fixedsys"> ShowTheText: <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke AppendText,hDlg,addr temp <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add esi,4 </font></p>
<p><font face="MS Sans Serif" size="-1">After inserting the function name/ordinal 
  into the edit control, we skip to the next <font color="#CCFFCC"><b>IMAGE_THUNK_DATA</b></font>.</font></p>
<p><font face="Fixedsys"> &nbsp;&nbsp;&nbsp; .endw <br>
  &nbsp;&nbsp;&nbsp; add edi,sizeof IMAGE_IMPORT_DESCRIPTOR </font></p>
<p><font face="MS Sans Serif" size="-1">When all <font color="#CCFFCC"><b>IMAGE_THUNK_DATA</b></font> 
  dwords in the array are processed, we skip to the next <font color="#CCFFCC"><b>IMAGE_IMPORT_DESCRIPTOR</b></font> 
  to process the import functions from other DLLs.</font></p>
<h3><font face="MS Sans Serif" size="-1">Appendix:</font></h3>
<p><font face="MS Sans Serif" size="-1">It would be incomplete if I don't mention 
  something about bound import. In order to explain what it is, I need to digress 
  a bit. When the PE loader loads a PE file into memory, it examines the import 
  table and loads the required DLLs into the process address space. Then it walks 
  the<font color="#CCFFCC"><b> IMAGE_THUNK_DATA</b></font> array much like we 
  did and replaces the<font color="#CCFFCC"><b> IMAGE_THUNK_DATAs</b></font> with 
  the real addresses of the import functions. This step takes time. If somehow 
  the programmer can predict the addresses of the functions correctly, the PE 
  loader doesn't have to fix the<font color="#CCFFCC"><b> IMAGE_THUNK_DATAs</b></font> 
  each time the PE file is run. Bound import is the product of that idea.<br>
  To put it in simple terms, there is a utility named <font color="#FFFFCC"><b>bind.exe</b></font> 
  that comes with Microsoft compilers such as Visual Studio that examines the 
  import table of a PE file and replaces the<font color="#CCFFCC"><b> IMAGE_THUNK_DATA</b></font> 
  dwords with the addresses of the import functions.When the file is loaded, the 
  PE loader must check if the addresses are valid. If the DLL versions do not 
  match the ones in the PE files or if the DLLs need to be relocated, the PE loader 
  knows that the precomputed addresses are not valid thus it must walk the array 
  pointed to by <font color="#CCFFCC"><b>OriginalFirstThunk</b></font> to calculate 
  the new addresses of import functions.<br>
  Bound import doesn't have much significance in our example because we use OriginalFirstThunk 
  by default. For more information about the bound import, I recommmend <a href="files/pe1.zip">LUEVELSMEYER's 
  pe.txt</a>.</font></p>
<hr>
<p align="center"><font face="MS Sans Serif" size="-1"><b>[<a href="http://win32asm.cjb.net">Iczelion's 
  Win32 Assembly Homepage</a>]</b></font></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -