现在的位置: 首页 > 综合 > 正文

The Smallest TCP Port Redirector

2013年08月07日 ⁄ 综合 ⁄ 共 19429字 ⁄ 字号 评论关闭
;====================[ The Smallest TCP Port Redirector ]=======================
;
;
;programmed by Holy_Father <holy_father@phreaker.net>
;Copyright (c) 2000,forever ExEwORx
;birthday: 8.9.2002
;version: 1.0
;
;compiled with MASM 6.14 with ALIGN:4
;total size: 2512b
;write no output, silently terminates when error
;it is multithreaded and stable on Windows NT 4.0, Windows 2000 and Windows XP
;
;usage: sredir.exe listen_on_port redir_to_ip redir_to_port
; redir_to_ip must be IP address in A.B.C.D format
;      no DNS implemented
;
;example: sredir.exe 100 212.80.76.18 80
;
;no other comments, cuz code is comment :)
;

.386p
.model flat, stdcall

include kernel32.inc
include winsock2.inc

LocalAlloc  PROTO :DWORD,:DWORD
LocalFree  PROTO :DWORD
ExitThread  PROTO :DWORD
ExitProcess   PROTO :DWORD
GetCommandLineA  PROTO
Sleep    PROTO :DWORD
CloseHandle  PROTO :DWORD
CreateThread  PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
TerminateThread  PROTO :DWORD,:DWORD
WaitForMultipleObjects  PROTO :DWORD,:DWORD,:DWORD,:DWORD

bind   PROTO :DWORD,:DWORD,:DWORD
listen   PROTO :DWORD,:DWORD
recv   PROTO :DWORD,:DWORD,:DWORD,:DWORD
send   PROTO :DWORD,:DWORD,:DWORD,:DWORD
closesocket  PROTO :DWORD
inet_addr  PROTO :DWORD
WSAIoctl  PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,
         :DWORD,:DWORD
WSAStartup   PROTO :DWORD,:DWORD
WSACleanup   PROTO
WSACreateEvent  PROTO
WSASocketA  PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
WSAConnect  PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
WSAEnumNetworkEvents PROTO :DWORD,:DWORD,:DWORD
WSAAccept  PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
WSAEventSelect  PROTO :DWORD,:DWORD,:DWORD
WSAWaitForMultipleEvents PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD

SOMAXCONN  equ 07FFFFFFFh
IPPROTO_TCP  equ 006h
SOCK_STREAM  equ 001h
AF_INET   equ 002h
FIONREAD  equ 04004667Fh
WAITFOREVENTSTIMEOUT equ 0FAh
WSA_WAIT_TIMEOUT equ 00102h
SOCK_ADDR_SIZE  equ 010h
FD_READ   equ 001h
FD_ACCEPT  equ 008h
FD_CLOSE  equ 020h
FD_ALL_EVENTS  equ 003FFh
LMEM_FIXED  equ 000h

.data

.code
start:
 mov ebp,esp          
 sub esp,001ECh;  保存一段堆栈空间
 lea eax,[ebp-01ECh];指向WSADATA的指针
 push eax
 push 0202h
 call WSAStartup; 启动socket
 test eax, eax   ;测试
 jnz @end    
        
 xor eax,eax       ;得到命令行参数
 call GetCommandLineA
 mov esi,eax      ;保存指针到esi
 xor eax,eax     
 lodsb              ;将命令行参数的第一个字节装入eax
 cmp al,022h      ;是否含有该死的"
 setz al          
 mov [ebp-004h],eax  ;将第一个字符保存到堆栈中
 @Next_char:
 lodsb                 ;装入下个字节
 test eax,eax         ;是否已经到达末尾
 jz @end               ;是。跳
 sub al,020h         ;是否为空格?
 jz @Space_found       ;是,跳 处理空格
 dec eax             ;是否是一个.
 dec eax
 setnz al              ;是就屏蔽掉
 and [ebp-004h],eax  ;
 jmp @Next_char     

 @Space_found:
 cmp byte ptr [ebp-004h],000h    ; 测试是否是尾部
 jnz @Next_char                 ;不是,找到一个参数

 call @Find_arg                
 mov edi,esi                    ;将edi设置为字符串指针
 push 020h                       ;为eax赋值
 pop eax 
 call @arg_len                  ;调用函数,得到参数长度
 mov ecx,eax                   ;保存字符串长度
 lea edi,[ebp-0100h]          
 push edi
 rep movsb                     ;将参数移动到堆栈
 mov [edi],cl                  ;为字符串加个null
 call @IntToStr              
 mov [ebp-004h],eax            ;把eax存入堆栈
 inc eax                      
 jz @end                         ;如果是0则字符串转化时出现错误,跳
 inc edi                       ;修改edi指针,查找下一个参数
 push edi
 call @Find_arg               
 xchg esi,edi
 push 020h
 pop eax
 call @arg_len       ;---------------+
 mov ecx,eax        ;               +
 xchg esi,edi        ;               +
 rep movsb          ;               +
 mov [edi],cl       ;               +
 call inet_addr;     ;               +
 mov [ebp-008h],eax ;               +
 inc eax            ;               +
 jz @end              ;               +
 call @Find_arg      ;               +
 inc edi            ;               +
 push edi            ;               +
 xchg esi,edi        ;               +
 xor eax,eax        ;               +
 call @arg_len       ;               +
 mov ecx,eax        ;               +-------下面的查找过程,和上面基本一直,不在废话鸟~
 xchg esi,edi        ;               +
 rep movsb          ;               +
 mov [edi],cl       ;               +
 call @IntToStr      ;               +
 mov [ebp-00Ch],eax ;               +
 inc eax            ;               +
   jz @end              ;               +
  
 mov eax,[ebp-00Ch] ;               +
 shl eax,010h       ;               +
 mov ax,[ebp-004h]  ;               +
 push eax            ;               +
 push dword ptr [ebp-008h]
 call @Server        ;               +
 @end:       
 call WSACleanup;    ;               +
 push 000h           ;               +
 call ExitProcess;   ;---------------+            

 @IntToStr:
 push esi         ;保存参数指针             
 xor eax,eax    ;清空eax,edx
 xor edx,edx
 mov esi,[esp+008h]      ;将edi的值存入esi。如果问为什么,自己去算下
 @IntToStr_next_char:
 lodsb                    ;像eax中装入一个字节
 test eax,eax            ;是否到达null
 jz @IntToStr_end         ;日,到了,跑路
 imul edx,edx,00Ah       ;edx=edx*10
 cmp al,030h            ;al是否为0
 jb @IntToStr_error       ;汗比0还小,跳
 cmp al,039h            ;是否为9
 ja @IntToStr_error       ;汗,比九大跳
 sub eax,030h          
 add edx,eax            ;转换完成
 jmp @IntToStr_next_char ;处理下一个字符
 @IntToStr_error:
 xor edx,edx            ;清空edx
 dec edx            
 @IntToStr_end:          
 mov eax,edx     
 pop esi
 ret

 @arg_len:    ;@arg -> edi, char -> eax
 push edi          ;指向参数的字符串
 xor ecx,ecx     
 dec ecx           ;比较是否已经到达空格,没有则重复
 repnz scasb        ;
 not ecx          ;这里说明一下,ecx为什么要设为-1,因为偶们的指针现在指向的是参数的尾部
 dec ecx          ;偶们要采取逆序的方法查找前一个空格,故设为负值在求反减1就能得到长度
 mov eax,ecx      ;如果不这样做,而采用调整指针,会浪费很多代码,不利于优化,这段代码值得大家学习的说
 pop edi
 ret

 @Find_arg:    ;str -> esi -> esi
  lodsb
  cmp al,020h
  jz @Find_arg
  dec esi
  ret

 @Server:              
 push ebp
 mov ebp,esp
 sub esp,034h          

; -030  - NewClient.Host.sin_family:Word
; -02E  - NewClient.Host.sin_port:Word
; -02C  - NewClient.Host.sin_addr:TInAddr
; -028..-024 - NewClient.Host.sin_zero:array[0..7] of Char
; -020  - NewClient.Socket:TSocket
; -01C  - TID:Cardinal;
; -018  - ServerEventHandle:THandle
; -014  - ServerHost.sin_family:Word
; -012  - ServerHost.sin_port:Word
; -010  - ServerHost.sin_addr:TInAddr
; -00C..-008 - ServerHost.sin_zero:array[0..7] of Char
; -004  - ServerSocket:TSocket
; +008  - FinalAddr:TInAddr
; +00C  - ListenPort:Word
; +010  - FinalPort:Word

 push esi
 push edi
 push ebx

 xor eax,eax
 mov [ebp-010h],eax              ;WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0,0)
 push eax                         ;建立一个套接字
 push eax
 push eax
 push IPPROTO_TCP
 push SOCK_STREAM
 push AF_INET
 call WSASocketA
 mov [ebp-004h],eax             ;讲套接字保存到堆栈
 inc eax                         ;是否建立失败,是,跳
 jz @Server_end

 mov eax,[ebp+00Ch]              ;将监听端口转换为网络顺序
 xchg ah,al                   
 mov [ebp-012h],ax              
 mov word ptr [ebp-014h],AF_INET ;使用IP地址家族

 push 010h                            
 lea eax,[ebp-014h]                 
 push eax
 push dword ptr [ebp-004h]
 call bind;                        绑定端口 bind(s,&serverhost.sin_family,10)实际上第二个参数中必须包含sin_family即可,故写为这种样子
 inc eax                          ;是否失败,是,跳
 jz @Server_end
 push SOMAXCONN                  
 push dword ptr [ebp-004h]
 call listen;                      监听端口listen(s,SOMAXCONN) 队列长度设为最大
 jnz @Server_end
 @Server_loop:                  
 lea eax,[ebp-018h]              ;进入事件循环
 push eax                         ;压入事件句柄
 push [ebp-004h]                  ;套接字
 call @EventSelect                ;选择要处理的事件
 test eax,eax                     ;失败?跳
 jz @Server_end 
 push [ebp-018h]                  ;再次压入句柄和套接字
 push [ebp-004h]       
 call @WaitForEvents              ;等待事件
 test eax,eax                     ;测试下 WSANETWORKEVENTS是否已经接收到数据
 jnz @Server_proc_events
 push 019h                        ;没有则休息下。避免占用资源,偶则跳,处理事件去鸟~~~~~
 call Sleep
 jmp @Server_loop                ;循环等待
 @Server_proc_events:
 and eax,FD_ACCEPT               ;是否是FD_ACCEPT事件
 jz @Server_loop                   ;不是,继续进入事件循环,等待下个事件
 xor eax,eax                     ;oh ,yeah!!!!!!!终于等到了
 push eax
 push eax
 push eax
 lea eax,[ebp-030h]              ;客户端IP地址
 push eax                  
 push dword ptr [ebp-004h]        ;偶们创建的套接字
 call WSAAccept;                 ;接收事件
 mov [ebp-020h],eax              ;把为客户端创建的套接字保存到缓冲区
 inc eax                         ;创建失败?继续进入事件循环
 jz @Server_loop            
 push 01Ch                
 push LMEM_FIXED
 call LocalAlloc;                  分配一个固定的内存
 test eax,eax                     ;分配失败?关闭套节字
 jz @Server_close_newsock
 mov ecx,[ebp-020h]              ;客户端套接字存入内存中
 mov [eax],ecx         
 lea esi,[ebp-030h]              ;取客户端地址
 lea edi,[eax+004h]              ;貌似要修改新套接字中的地址了,其实偶这里比较糊涂,只是从代码上推断
 movsd                             ;
 movsd                             ;---------开始修改
 movsd                             ;
 movsd                             ;    
 lea esi,[ebp+008h]              ;修改FinalAddr,晕这是什么?????????????????、
 movsd
 movsd

 lea ecx,[ebp-01Ch]             ;取线程ID指针,看来要对线程动手了:)
 push ecx                        ;压
 xor ecx,ecx
 push ecx
 push eax                        ;压入分配的内存
 push offset @NewClientThread    ;压入线程参数地址
 push ecx                       
 push ecx
 call CreateThread;              bingo,创建线程
 jmp @Server_loop               ;该事件处理完毕,继续进入事件循环,等待下一个事件
 @Server_close_newsock:
 push dword ptr [ebp-020h]
 call CloseSocket
 jmp @Server_loop
 @Server_end:
 push dword ptr [ebp-018h]
 call CloseHandle
 push dword ptr [ebp-004h]
 call CloseSocket
 jmp @end

 @EventSelect:
 call WSACreateEvent;建立一个时间  WSACreateEvent(VOID)
 test eax,eax      ;测试是否建立成功
 jz @EventSelect_fail ;失败则退出
 mov ecx,[esp+008h] ;
 mov [ecx],eax       ;保存事件指针

 push FD_ALL_EVENTS
 push eax
 push [esp+00Ch]
 call WSAEventSelect;筛选事件 WSAEventSelect(S,Thanlde,FD_ALL_EVENT)
 inc eax
 jnz @EventSelect_end ;测试是否失败,失败就跳
 @EventSelect_fail:
 xor eax,eax
 @EventSelect_end:
 ret 008h         ;平衡堆栈

 @WaitForEvents: 
 push ebp        
 mov ebp,esp
 sub esp,02Ch
 push 000h                            ;函数返回后,完成的例程不被执行
 push WAITFOREVENTSTIMEOUT           
 push 000h                            ;一接到信号就返回
 lea eax,[ebp+00Ch]            
 push eax                             ;设置事件句柄数组
 push 1                               ;指定一个数组
 call WSAWaitForMultipleEvents;       ;;;;;;;;;;;;;;;;这个函数没用过,所以不能说清楚,看MSDN把自己
  inc eax                        
 jz @WaitForEvents_end                 ;失败就跳
 sub eax,WSA_WAIT_TIMEOUT+1          ;测试下是否是超时返回(不清楚)
 jz @WaitForEvents_end
 lea eax,[ebp-02Ch]                  ;为WSANETWORKEVENTS分配个缓冲区,不知道能不能溢出,挖嘎嘎~~~~
 push eax                             ;一个缓冲区 
 push dword ptr [ebp+00Ch]            ;世界安句柄
 push dword ptr [ebp+008h]            ;套接字
 call WSAEnumNetworkEvents
 inc eax                            
 jz @WaitForEvents_end                 ;出错?跳
 mov eax,[ebp-02Ch]                  ;WSANETWORKEVENTS的指针装入eax
 @WaitForEvents_end:
 leave                                  ;平衡堆栈
 jmp @EventSelect_end                 ;******************************终于注释完了最乱的一段了************************

 @NewClientThread:
 mov ebp,esp
 sub esp,070h

; -070  - RedirThreadHandle:THandle
; -06C  - ClientThreadHandle:THandle
; -068  - Redir.ThreadArgs.MainItem:PTcpItem
; -064  - Redir.ThreadArgs.OtherItem:PTcpItem
; -060  - Redir.ThreadArgs.ThreadType:Cardinal
; -05C  - Redir.ThreadArgs.Events:Longint
; -058  - Redir.ThreadArgs.EventHandle:THandle
; -054  - Redir.ThreadArgs.Active:Boolean
; -050  - Redir.ThreadArgs.Host.sin_family:Word
; -04E  - Redir.ThreadArgs.Host.sin_port:Word
; -04C  - Redir.ThreadArgs.Host.sin_addr:TInAddr
; -048..-044 - Redir.ThreadArgs.Host.sin_zero:array[0..7]
; -040  - Redir.ThreadArgs.Socket
; -038  - Redir.ThreadID:Cardinal
; -034  - Client.ThreadArgs.MainItem:PTcpItem
; -030  - Client.ThreadArgs.OtherItem:PTcpItem
; -02C  - Client.ThreadArgs.ThreadType:Cardinal
; -028  - Client.ThreadArgs.Events:Longint
; -024  - Client.ThreadArgs.EventHandle:THandle
; -020  - Client.ThreadArgs.Active:Boolean
; -01C  - Client.ThreadArgs.Host.sin_family:Word
; -01A  - Client.ThreadArgs.Host.sin_port:Word
; -018  - Client.ThreadArgs.Host.sin_addr:TInAddr
; -014..-010 - Client.ThreadArgs.Host.sin_zero:array[0..7]
; -00C  - Client.ThreadArgs.Socket
; -008  - Client.ThreadArgs.Connected
; -004  - Client.ThreadID:Cardinal
; +004  - AArgs:Pointer
;  +000  AArgs.NewSocket
;  +004  AArgs.NewHost.sin_family:Word
;  +006  AArgs.NewHost.sin_port:Word
;  +008  AArgs.NewHost.sin_addr:TInAddr
;  +00C..+010 AArgs.NewHost.sin_zero:array[0..7] of Char
;  +014  AArgs.FinalAddr:TInAddr
;  +018  AArgs.ListenPort:Word
;  +01A  AArgs.FinalPort:Word

 xor eax,eax
 lea edi,[ebp-070h]
  push 01Ch                       
 pop ecx          
 rep stosd            ;初始化堆栈0x70-0x54的部分

 push eax
 push eax
 push eax
 push IPPROTO_TCP
 push SOCK_STREAM
 push AF_INET
 call WSASocketA;       建立一个client套接字 WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0,0)
 mov [ebp-00Ch],eax
 inc eax
 jz @NewClientThread_close_newsock;创建错误,清理

 push 001h       
 pop eax           ;为eax赋值
 mov [ebp-020h],eax;将BOOLEN值都设为真
 mov [ebp-054h],eax
 mov [ebp-060h],eax

 mov edx,[ebp+004h];   把新套接字的指针装入edx
 movzx ax,byte ptr [edx+01Ah]
 xchg ah,al             ;转为网络地址
 mov [ebp-01Ah],ax     ;送回到缓冲区中
 mov word ptr [ebp-01Ch],AF_INET  ;使用IP地址家族
 mov eax,[edx+014h]               ;把新套接字的地址入eax
 mov [ebp-018h],eax               ;存入缓冲区
 mov eax,[edx]                   
 mov [ebp-040h],eax               ;新套接字存入缓冲区
 lea esi,[edx+004h]               ;新套接字地址移动到缓冲区
 lea edi,[ebp-050h]
 movsd          ;--------------------------+
 movsd          ;                          +-----------开始移动
 movsd          ;                          +
 movsd          ;--------------------------+

 lea eax,[ebp-058h]               ;取事件句柄地址
 push eax                          ;压入
 push dword ptr [ebp-040h]         ;原来的那个套接字
 call @EventSelect                 ;暴汗!!!!!!怎么又进入事件体了
 test eax,eax
 jz @NewClientThread_close_clientsock

 lea eax,[ebp-068h]               ;取PTcpItem看来要替换TCP里的西西了,继续看他干什么,不过ptcpitem里面不是0吗??
 mov [ebp-030h],eax               ;把地址装入了客户端的otheritem.PTcpItem
 mov [ebp-068h],eax               ;地址又回送了,看来构造了个指向指针的指针
 lea eax,[ebp-034h]               ;取客户端mainitem.ptcpitem地址
 mov [ebp-034h],eax               ;再次构造了一个指针指针
 mov [ebp-064h],eax               ;送入otheritem.ptcpitem中;           看来运行后,地址被替换了other->main main->other
                                      ;他要干什么???????
 lea eax,[ebp-004h]               ;客户端线程ID地址
 push eax
 push 000h
 lea eax,[ebp-034h]               ;压入MainItem:PTcpItem地址
 push eax
 push offset @ThreadProc           ;压入线程处理函数地址
 push 000h                        
 push 000h
 call CreateThread;                晕迷~~~又建了个线程
 test eax,eax
 jz @NewClientThread_close_clientsock
 mov [ebp-06Ch],eax              ;保存客户端线程句柄

 push 019h
 call Sleep                       ;终于休息了,防止占用过多的资源
 lea eax,[ebp-038h]
 push eax                        
 push 000h
 lea eax,[ebp-068h]
 push eax
 push offset @ThreadProc
 push 000h
 push 000h
 call CreateThread;                再次创建线程,是不是他打算为接受和转发个创建一个线程
 test eax,eax
 jz @NewClientThread_term_clientthread
 mov [ebp-070h],eax               ;句柄保存

 push -001h
 push 000h
 lea eax,[ebp-070h]
 push eax
 push 002h
 call WaitForMultipleObjects;      有是这个偶不熟悉的API,不多说了,避免误人子弟
 xor eax,eax
 mov [ebp-054h],eax               ;如果句柄创建成功就保存参数
 mov [ebp-020h],eax
 mov [ebp-008h],eax
 push 032h                        ;休息
 call Sleep

 push dword ptr [ebp-040h] ;清理套接字,主套接字和新套接字
 call CloseSocket
 push dword ptr [ebp-00Ch]
 call CloseSocket

 push 0FAh   ;防止线程退出过快,呼呼一段时间,给系统清理的时间
 call Sleep

 push 000h   ; 终止线程,个人认为这是一种比较不好的退出线程的方法,建议看下win32多线程编程
 push dword ptr [ebp-070h]
 call TerminateThread;------------------------------------------+
 @NewClientThread_term_clientthread:;                              +
 push 000h            ;                                         +
 push dword ptr [ebp-06Ch]:             ;                       +
 call TerminateThread;                                          +
 @NewClientThread_close_clientsock:;                               +
 push dword ptr [ebp-00Ch];                                     +----------线程和套接字清理的西西,没什么好说的
 call CloseSocket;                                              +
;                                                                  +
 push dword ptr [ebp-058h];                                     +
 call CloseHandle;                                              +
 push dword ptr [ebp-024h];                                     +
 call CloseHandle;----------------------------------------------+

 @NewClientThread_close_newsock:
 mov eax,[ebp+004h] 
 push dword ptr [eax]
 call CloseSocket
 push dword ptr [ebp+004h]
 call LocalFree;释放内存
 push 000h
 call ExitThread;清理线程

 @ThreadProc:
 mov ebp,esp
 sub esp,00Ch

; -00C  - LBuffer:Pointer
; -008  - LBytes:Cardinal
; -004  - LSocket:TSocket
; +004  - AArgs:Pointer
;  +000  AArgs.ThreadArgs.MainItem:PTcpItem
;  +004  AArgs.ThreadArgs.OtherItem:PTcpItem
;  +008  AArgs.ThreadArgs.ThreadType:Cardinal
;  +00C  AArgs.ThreadArgs.Events:Longint
;  +010  AArgs.ThreadArgs.EventHandle:THandle
;  +014  AArgs.ThreadArgs.Active:Boolean
;  +018  AArgs.ThreadArgs.Host.sin_family:Word
;  +01A  AArgs.ThreadArgs.Host.sin_port:Word
;  +01C  AArgs.ThreadArgs.Host.sin_addr:TInAddr
;  +020..+024 AArgs.ThreadArgs.Host.sin_zero:array[0..7]
;  +028     AArgs.ThreadArgs.Socket
;  +02C     AArgs.ThreadArgs.Connected - client only
 
 mov esi,[ebp+004h]
 mov eax,[esi+008h]
 test eax,eax
 jnz @ThreadProc_redir ;这两个值是否相等,不等?修正
 mov eax,[esi+02Ch]   ;测试客户端是否被连接
 test eax,eax
 jnz @ThreadProc_client_connected
 push eax
 push eax
 push eax
 push eax
 push SOCK_ADDR_SIZE
 lea eax,[esi+018h]
 push eax
 push dword ptr [esi+028h]
 call WSAConnect;如果为0,调用WSAConnect进行连接
 inc eax
 jz @ThreadProc_error;连接错误?跳
 lea eax,[esi+010h]
 push eax
 push dword ptr [esi+028h]
 call @EventSelect;继续使用EventSelect筛选事件
 mov [esi+02Ch],eax
 test eax,eax
 jz @ThreadProc_error
 jmp @ThreadProc_client_connected;找到事件,跳
 @ThreadProc_redir:
 mov edi,[esi+004h]
 @ThreadProc_redir_waitforcon:
 push 019h
 call Sleep
 mov eax,[edi+02Ch]
 test eax,eax
 jz @ThreadProc_redir_waitforcon
 @ThreadProc_client_connected:
 mov eax,[esi+014h];测试下是否处于活跃状态
 test eax,eax
 jz @ThreadProc_closesock;程序已经关闭,清理套接字
 mov eax,[esi+004h];
 mov eax,[eax+014h]
 test eax,eax
 jz @ThreadProc_closesock

 push dword ptr [esi+010h]
 push dword ptr [esi+028h]
 call @WaitForEvents;已经连接,等待事件发生

 test eax,eax      ;测试是否有被筛选事件发生
 jz @ThreadProc_client_connected;没有,跳,继续等待连接
 mov [esi+00Ch],eax  ;将WSANETWORKEVENTS的指针存入参数AArgs.ThreadArgs.Events:Longint
 and eax,FD_READ     ;测试是否含有FD_READ
 jnz @ThreadProc_read ;含有,跳到该事件的例程中
 @ThreadProc_af_read:
 mov eax,[esi+00Ch] 
 and eax,FD_CLOSE     ;是否已经关闭了?是,跳,继续等待(汗,变的不会这么块把)
 jnz @ThreadProc_closesock
 jmp @ThreadProc_client_connected
 @ThreadProc_read:
 push dword ptr [esi+028h]   ;压入socket
 call @BytesToRecv           ;接收数据,得到接收的数据size
 test eax,eax                ;什么都没收到?
 jz @ThreadProc_af_read       ;跳,继续读
 mov edi,eax                ;接收的数据size保存到edi
 push eax                    ;压入
 push LMEM_FIXED             ;为数据分配内存
 call LocalAlloc
 test eax,eax                ;失败?
 jz @ThreadProc_closesock     ;清理套接字,跑路~
 mov [ebp-00Ch],eax         ;保存指针  
 push 000h                  
 push edi
 push eax
 push dword ptr [esi+028h]
 call recv;                  用继续recv()接收剩下的
 mov [ebp-008h],eax        ;保存字节数
 inc eax                   ;接收失败?跳
 jz @ThreadProc_read_free
 @ThreadProc_read_loop:
 push 000h               
 push dword ptr [ebp-008h] ;压入接收的字节数
 push dword ptr [ebp-00Ch] ;缓冲区地址,由LocalAlloc分配
 mov eax,[esi+004h]       ;OtherItem:PTcpItem保存到eax
 mov eax,[eax+028h]       ;压入套接字,其实偶也不知道如何得到的套接字 :(
 push eax
 call send;                 发送数据
 inc eax               
 jz @ThreadProc_read_free   ;发送失败?跳
 dec eax                  ;恢复返回值
 sub [ebp-008h],eax       ;得到没有被发送的字节数
 jnz @ThreadProc_read_loop ;是否该值为0,即是否全部发送,否?跳
 @ThreadProc_read_free:
 push dword ptr [ebp-00Ch]  ;处理读数据失败的代码
 call LocalFree;             清理下内存,然后继续跳
 jmp @ThreadProc_read
 @ThreadProc_closesock:       
 push dword ptr [esi+028h]  ;压入套接字,关闭套接字,清理内存
 call CloseSocket
 @ThreadProc_error:            ;退出线程
 push 000h
 call ExitThread

 @BytesToRecv:;             这部分 没什么难度。自己看把
 xor eax,eax          
 push eax
 push eax
 push eax
 push eax
 lea ecx,[esp+00Ch]
 push ecx
 push 004h
 sub ecx,004h
 push ecx
 push eax
 push eax
 push FIONREAD
 push [esp+02Ch]
 call WSAIoctl
 inc eax
 jz @BytesToRecv_end
 mov eax,[esp]
 @BytesToRecv_end:
 pop ecx
 pop ecx
 ret 004h

end start 

抱歉!评论已关闭.