I. Preface
The computer (calc.exe) Program has existed for a long time in windows and is also a very common software. But in general, it displays Arabic numbers, and there is no switching between character display. This time I will discuss in two articles how to make the calculator program display Chinese characters and numbers. This article discusses the basic principles of modification, and the next article discusses how to implement programming.
Ii. Analysis of modification principles
In many of my previous articles, I have always stressed that Windows programming is actually a pile of various API functions. who has mastered more API functions, then he can write out powerful software with complete functions. Of course, writing excellent software is determined by other factors, but the degree of API mastery remains the focus. Back in this topic, although the calculator program was released by Microsoft, the software giant, basically it does not use many advanced technologies. As I said, it is implemented by the accumulation of many API functions. Our purpose is to modify the display of the program, so it is necessary to find the related functions in the calculator program, clarify the functions of the related functions, and then study. After everything is clear, you can program the changes. After understanding the general idea, we need to analyze the API functions in the calculator.
Iii. Search for target API functions
When an executable file uses code or data from another DLL, it is called an import. When a PE file is loaded, one of the work of the Windows loader is to locate all the imported functions and data, and let the files being loaded use those addresses. This process is completed through the import table of the PE file. The import table stores the information required for dynamic links such as the function name and its resident DLL name. Therefore, we need to parse the import table of the calculator to see which API functions it contains.
Of course, you can use professional viewing tools, such as peid:
Figure 1 use peid to view the import table
It is really convenient to use professional software, but I think it is more important for an engineer to know how the program works. Here is a Win32 console application. Its main function is to find and enumerate the import table in the EXE program. The Code is as follows:
#include <windows.h>#include <DbgHelp.h>#include <stdio.h>#pragma comment(lib,"DbgHelp.lib")#define FILENAME "calc.exe" //欲枚举导入表的文件名int main(){ int i, j; HANDLE hFile = NULL; HANDLE hMap = NULL; LPVOID lpBase = NULL; //打开PE文件 hFile = CreateFile(FILENAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { printf("文件打开失败!\n"); return 0; } //创建一个想共享的文件数据句柄 hMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,0); if (hMap == NULL || hMap == INVALID_HANDLE_VALUE) { printf("创建文件映像失败!"); CloseHandle(hFile); return 0; } //获取共享的内存地址 lpBase = MapViewOfFile(hMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0); if (lpBase == NULL) { printf("获取共享的内存地址失败!"); CloseHandle(hMap); CloseHandle(hFile); return 0; } PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBase; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((BYTE *)lpBase + pDosHeader->e_lfanew); DWORD Rva_import_table = pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; if(Rva_import_table == 0) { printf("无导入表!"); UnmapViewOfFile(lpBase); CloseHandle(hMap); CloseHandle(hFile); return 0; } PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)ImageRvaToVa( pNtHeader, lpBase, Rva_import_table, NULL ); //减去内存映射的首地址,就是文件地址了 printf("FileAddress Of ImportTable: %p\n", ((DWORD)pImportTable - (DWORD)lpBase)); //现在来到了导入表的面前:IMAGE_IMPORT_DESCRIPTOR 数组(以0元素为终止) //定义表示数组结尾的null元素 IMAGE_IMPORT_DESCRIPTOR null_iid; IMAGE_THUNK_DATA null_thunk; memset(&null_iid, 0, sizeof(null_iid)); memset(&null_thunk, 0, sizeof(null_thunk)); //每个元素代表了一个引入的DLL。 for(i=0; memcmp(pImportTable + i, &null_iid, sizeof(null_iid))!=0; i++) { LPCSTR szDllName = (LPCSTR)ImageRvaToVa( pNtHeader, lpBase, pImportTable[i].Name, //DLL名称的RVA NULL); //获取DLL名称 printf("-----------------------------------------\n"); printf("[%d]: %s\n", i, szDllName); printf("-----------------------------------------\n"); //我们来到该DLL的 IMAGE_TRUNK_DATA 数组(IAT:导入地址表)前面 PIMAGE_THUNK_DATA32 pThunk = (PIMAGE_THUNK_DATA32)ImageRvaToVa( pNtHeader, lpBase, pImportTable[i].OriginalFirstThunk, NULL); for(j=0; memcmp(pThunk+j, &null_thunk, sizeof(null_thunk))!=0; j++) { //这里通过RVA的最高位判断函数的导入方式, //如果最高位为1,按序号导入,否则按名称导入 if(pThunk[j].u1.AddressOfData & IMAGE_ORDINAL_FLAG32) { printf("\t [%d] \t %ld \t 按序号导入\n", j, pThunk[j].u1.AddressOfData & 0xffff); } else { //按名称导入,我们再次定向到函数序号和名称 //注意其地址不能直接用,因为仍然是RVA PIMAGE_IMPORT_BY_NAME pFuncName = (PIMAGE_IMPORT_BY_NAME)ImageRvaToVa( pNtHeader, lpBase, pThunk[j].u1.AddressOfData, NULL); printf("\t [%d] \t %ld \t %s\n", j, pFuncName->Hint, pFuncName->Name); } } } UnmapViewOfFile(lpBase); CloseHandle(hMap); CloseHandle(hFile); getchar(); return 0;}
The code will not be explained in detail. You can refer to PE-related books to learn about the location and format of the imported table. The running result is as follows:
Figure 2 self-programmed search API functions
From the results, we can see that the program we wrote is consistent with the peid display result, indicating that our program is correct and valid. You can view all the listed API functions and find that both setwindowtextw () and setdlgitemtextw () can display text in the text box. Because setdlgitemtextw () calls setwindowtextw () internally, it is assumed that the real function is the setwindowtextw () function. The next step is to test the function.
4. Lock real API functions In msdn, The setwindowtextw () function is defined as follows:
BOOL SetWindowText( HWND hWnd, // handle to window or control LPCTSTR lpString // title or text);
The first parameter of this function is the window handle, and the second parameter is a string pointer, that is, the content to be displayed. It can be seen that the second parameter is the focus. Now open od to find this function. (Note: I am using ollydbg v2.01 here. If it is v1.10, the corresponding results may not be obtained.) load the calculator program in OD, right-click, select "All intermodular CILS" in "search for" and enter setwindowtextw. The result is as follows:
Figure 3 Use od to find the corresponding function
The call address of the function is quickly locked, and a breakpoint is placed at this location to facilitate debugging. Run F9 to the breakpoint as follows:
Figure 4 View function parameters
In the Stack window in the lower-right corner and the data window in the lower-left corner, you can determine that the second parameter of setwindowtextw () is "0" and the code value is 0x30. This is the value displayed in the output box of the calculator when the calculator is started. Let's try to change "0" to "0 ". If the code value of the Chinese character "zero" is "96f6", you can directly edit the data window:
Figure 5 modify the numeric value
Note that this is a small-end display, so you should enter it in reverse order. After modification, press F9 to run:
Figure 6 running Calculator
In this case, the Chinese characters are displayed in the calculator. We can think that setwindowtextw () Is the function we are looking. Of course, you can try more here for the sake of insurance. For example, if you press "1" in the calculator, the OD will be disconnected from the setwindowtextw () function. At this time, the string pointer address of parameter 2 will change, but the principle is the same, modify it to the value of the Chinese character "one" for testing. Of course, interested readers can also try to use this method to test the setdlgitemtextw () function. I will not go into details here.
V. Summary This article explains the basic idea of program modification. With this idea, we can customize many functions for the program. After all, reverse engineering is to analyze the target object to understand its implementation mechanism, so as to improve the deficiencies and add new ideas. This laid the theoretical foundation for my later articles. The specific code implementation will be detailed in the next article.
003rd reverse engineering: display Chinese characters in the calculator Program (I)