汇编端口转发程序

注释了holy_father写的这个端口转发的程序,虽然注释了大部分代码,本人还是不敢说把代码完全
搞懂了,比如转发的过程偶就不是很明白,如果那个大牛了解这个程序端口转发的过程,请指导偶一
下下,如果那个朋友有不懂得地方或者发现偶注释错误的地方.
//

;====================[ The Smallest TCP Port Redirector ]=======================
;
;
;
;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                 ;******************************终于注释完了最乱的一段了************************ 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值