The Smallest TCP Port Redirector

硬件精灵Unknown Device Identifier:未知设备识别与驱动解决方案工具 我们常说“驱动是硬件的灵魂”,这句话虽然有点文艺,但非常贴切。准确地说:🔧硬件驱动程序是操作系统内核与物理设备之间的中介软件,负责将高层系统调用翻译为底层硬件可执行的指令。听起来抽象?来个具体例子。当你按下键盘上的“A”键时,发生了什么?键盘控制器检测到电路通断;发送中断信号给CPU;操作系统收到中断后,调用USB HID驱动处理数据包;驱动解析出扫描码0x1E;最终转换为字符”A”输入到文本框中。整个过程里,如果没有usbhid。 阅读详情
;====================[ 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 

COM-Redirecter 串口转TCP/IP,TCP/IP转虚拟串口 串口转TCP/IP,TCP/IP转虚拟串口;COM-Redirecter 串口转TCP/IP,TCP/IP转虚拟串口 立即下载

相关推荐

WIN764位驱动加载免签名

WIN764位驱动加载免签名

SQL sever 2008安装 失败原因 和解决方法

重启电脑 SQL server 2008在安装程序支持规则检查中出现需重启电脑的提示,并经过多次重启,也无用的情况下,可以使用下面的方法来解决该问题 解决办法 这时进入注册表编辑器,依次打开HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager,找到“PendingFileRenameOperations”,删除。 数...

qq_42831621的博客 4226

TCP Redirector-开源

Tcpredir:通过另一台计算机重定向TCP通信。 如果您位于讨厌的防火墙后面,但对可以访问Internet的远程计算机的访问权限受到限制,则很有用。 任意数量的连接。 感觉就像是透明访问。

VS中编译64位程序以及遇到的问题(E0000235)

安装64位操作系统不是编译64位程序的必要条件,关键是要装64位程序的编译器。虽然标题写着如何在VS2008中编译,但其实2005也是类似。 1. 选择“Build” – “Configuration Manager”菜单,打开配置管理器。点击新建解决方案平台。 2. 选择“x64”平台,点击确定按钮。 3. 这时候配置管理器中的平台已经改成刚才选择的x64了,这时候编译出来的就

whatday的专栏 1万+

CDO批量处理nc文件:5分钟搞定CMIP6数据双线性插值(附完整代码)

本文详细介绍了如何使用CDO工具链中的`remapbil`命令,快速实现CMIP6数据的批量双线性插值处理。通过环境配置、核心操作步骤、高级优化技巧及典型报错解决方案,帮助科研人员高效处理大规模nc文件,显著提升气象数据处理效率。

weixin_29267307的博客 296

头歌操作系统 课堂练习4.2:页式内存管理 答案 无解析

头歌操作系统 课堂练习4.2:页式内存管理 答案 无解析

kercii的博客 1万+

两个驱动程序安装错误

我的驱动程序在32位平台上可以安装,在64位平台上却不能安装,但在64位平台上用手动安装的方法也能安装成功。 在64位平台上搭建了一个开发环境,对安装程序进行跟踪调试,发现在调用 SetupDiCallClassInstaller 函数时出错,用GetLastError()看了一下错误码,是 0x e0000235, 这是个ERROR_IN_WOW64错

newkelt的专栏 6212

SAP采购订单中项目类别B(限制)的控制逻辑

在笔者所在企业中,框架类采购订单中项目类别需要选择B(限制)。今天笔者从比较全面的角度分析了一下这个项目类别B到底可以决定些什么?控制到什么?先从后台SPRO中打开相应的配置菜单。 打开项目类别B之后,可以看到一些配置信息,这里有一点与其它配置不同的地方,即无法新增项目,也无法修改现有项目。这个疑惑今后再去解决吧。当前只研究项目类别B的控制逻辑。 下面就参考上图中的配置分段来分析和测试其控制逻辑, 1、如项目类别配置图,所需材料值为不允许;经测试,如下图在采购订单创建时,不能输入物料编号条目。

专注SAP应用技术文章写作,致力于拉近用户与系统间的距离; 6035

64位Win7系统安装TCP/IP转虚拟串口驱动COM-redirector出错

 出现“CallClassInstaller(REGISTERDEVICE) FAILURE:(0xe0000235) 的对话框。 我看搜索了一下,说是,64位系统的驱动需要数字签名,我就按照百度经验的 ”win7 64位系统如何禁用数字签名“的方法,禁止了数字签名,还是不行。 怎么办?

coolsoloist的专栏 4569

泛微OA E9文档管理优化:临时文件清理与存储配置指南

本文深入解析了泛微OA E9系统性能下降的常见原因——临时文件堆积,并提供了完整的优化配置指南。文章详细介绍了临时文件的产生机制,并手把手指导管理员如何通过修改存储路径、调整保留时间、设置白名单等关键配置,有效清理与管理系统临时文件,从而释放存储空间,提升系统运行效率与稳定性。

tree8的博客 432

DPABINet保姆级教程:零代码完成脑网络分析与图论计算

本文提供DPABINet的零代码脑网络分析全流程指南。该工具通过图形化界面集成时间序列提取、连接矩阵构建、图论指标计算及统计分析,大幅降低技术门槛。重点解析了阈值选择、二值化与小世界属性计算等关键步骤,帮助研究者快速掌握脑网络分析与图论计算,提升科研效率与可重复性。

j2k3l4的博客 671

windows下使能/关闭硬件

windows下禁用/启动设备

guolisong的专栏 720

计算机视觉——多视图几何

多视图几何1.前言1.1 多视图几何概念2. 基本原理2.1 对极几何2.2 基础矩阵2.2.1 基础矩阵推导2.2.2 求解基础矩阵3. 实验过程3.1 实验数据准备3.2 实验代码3.3 实验结果及分析4. 实验中遇到的问题 1.前言 1.1 多视图几何概念 多视图几何是利用在不同视点所拍摄图像间的关系,来研究照相机之间或者特征之间关系的一门科学。 多视图几何(Multiple View ...

RuiMa的博客 7715

Windows Filtering Platform 结构和简介

这两天一直在写一个用tdi实现的tcp Redirector ,说白了就是一个tcp连接的重定向器,本来已经写的差不多了,前两天在google上搜索tdi的关键字时一不小心连接到在线msdn上,却看见一个噩耗,Windows vista已经不再支持tdi驱动,替代的方案是Windows Filtering Platform和Winsock Kernel。          缓过神来心想

xiaoqiangvs007的专栏 5509

MacOS多次踩坑后成功安装Homebrew

来一次性成功安装Homebrew吧 官网提供的安装脚本无法成功安装Homebrew,原因大家都懂的,故采用脚本安装的方式。 下载homebrew的安装脚本brew_install 在Download路径下执行如下脚本 curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install >> brew_install 修改brew_install脚本 修改brew_install脚本。如果你的脚本打开之后是如下

weixin_41847116的博客 1983

Hindsight 内存爆炸 4 个词排查清单:9,284 条 6 成是 SSH 调试日志——Agent 标签系统的实战复盘

9,284 条记忆里 66% 是 SSH 调试日志。4 个标签被滥用=0 区分度。3 个 entity_labels + retain_mission + retain_every_n_turns 配置把噪声压回 5%——附 PATCH 脚本和实测前后数据。

Starry-SkyJing的博客 59

Win7 32 不能安装STM32 虚拟串口驱动解决方法

1、  对于一些精简过的系统,无法安装虚拟串口,是由于系统缺少mdmcpq.inf和usbser.sys文件所造成的。只需要将文件下载下来放在相应的文件夹下面就行了。 文件对应的目录如下: mdmcpq.inf在C:\WINDOWS\INF目录; usbser.sys在C:\WINDOWS\SYSTEM32\DRIVERS\目录。   2、修改mdmcpq.inf

云志的技术博客专栏 1万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

安装 Realtek HD Audio Driver 失败 Error Code : 0xE0000100

更新声卡驱动提示“安装Realtek HD Audio Driver失败.Error Code:0xE0000100]”,错误, 尝试各种版本驱动无效,以下是解决方案: 1. 下载windows7声卡驱动修复压缩包(直接复制以下下载地址下载:http://ishare.iask.sina.com.cn/f/5851516.html/下载 ). 2. 打开你win7系统的所在盘逐步进入Wind

sun_168的专栏 3万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

模型之外的那套装置:用 AI harness 完成一个三端同步应用

AI harness 指模型之外、让模型能持续产出可交付软件的全部工程装置。本文把它称作"支架"。它由五层构成:输入层规定模型读什么,反馈层规定模型怎么知道自己错了,观测层把界面与设备状态变成可读事实,记忆层让跨会话不失真,边界层规定哪些动作不许模型自行作出。支架的价值在六天里可以直接计量。

Leo的Matrix 183

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

上一篇: 不要被假象迷惑 网络安全的七大误区
下一篇: 未来网络安全十大趋势
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值