Keep Server Online
If you find the Apache Lounge, the downloads and overall help useful, please express your satisfaction with a donation.
or
A donation makes a contribution towards the costs, the time and effort that's going in this site and building.
Thank You! Steffen
Your donations will help to keep this site alive and well, and continuing building binaries. Apache Lounge is not sponsored.
| |
|
Topic: perl - cron - mod_security25x and ipfw |
|
Author |
|
fingers
Joined: 21 Apr 2008 Posts: 7
|
Posted: Sun 04 May '08 13:42 Post subject: perl - cron - mod_security25x and ipfw |
|
|
Just thought someone might be interested in this little script I modified from apache2-linux-iptables to apache2-windows-ipfw. Used on windows2000 (ie no builtin firewall)
It allows you to create firewall rules in ipfw from mod_security25x exec: rule
http://www.icsr.agh.edu.pl/~polak/skrypty/ban-hackers.var
Quote: |
Description
The BAN-HACKERS is a PERL script which enables blocking access to your WWW server for potential hackers. It cooperates with the ModSecurity web application firewall. Every IP address catched by the firewall is automatically added to the "iptables" netfilter and to a SQLite database. This database also remebers when the IP was added, so after specified time every IP address can be purged from the database and from "iptables". You can also define a "whitelist" - its elements are never added to the DB and to iptables.
|
I use it along with mod_limit and other mod_security rules to block "ANY" user_agents -- libwww-perl.... yes I know this might stop legit use but you can whitelist the ip's etc
Code: |
#!c:/perl/bin/perl.exe -w
# $Revision: 1.1 $
# $Source: /usr/local/cvsroot/boxes/scripts/brave/ban-hackers.pl,v $
# %Location: /usr/local/sbin/
# %Servers: brave
# Every minute check the database for new ip# to ban
#* * * * * c:\perl\bin\perl.exe c:/apache228/bin/ban-hackers.pl add
#
# Every hour purge expired entries
#0 * * * * c:\perl\bin\perl.exe c:/apache228/bin/ban-hackers.pl purge
#
# to see the entries use /banhackers.pl list
# SecRule RESPONSE_STATUS "^418$" "exec:/usr/local/apache2/bin/ban-hackers.pl,msg:'Address has been blocked',severity:5,phase:5"
# script to take ip# hit by rules in apache mod_security
# and feed them to iptables to ban access to port 80 (http)
# BAN-HACKERS.PL written by Stanislaw Polak
# http://www.icsr.agh.edu.pl/~polak/
# 30 Nov 2006
#
# Copyright (c) 2006 Stanislaw Polak
# Unpublished work.
# Permission granted to use and modify this script so long as the
# copyright above is maintained, modifications are documented, and
# credit is given for any use of the script.
#
# For more information, see:
# http://www.icsr.agh.edu.pl/~polak/skrypty/ban-hackers.var
#
#Version 1.03 (7 Apr 2008)
# Some modifications made by Dan MacNeil
#Version 1.02 (24 Jan 2007)
# Locking was added
#Version 1.01 (27 Dec 2006)
# Problems with deleting a few the same rules has been fixed
#Version 1.0 (30 Nov 2006)
# The first public version
######################################################################################################
# Requirements: grep installed and DBD::SQLite for perl
# You Need to create the log file and you have to have "ipfw for windows" installed, of course
######################################################################################################
use DBI;
use strict;
use Fcntl qw (:flock);
my($ip,$rule,$dbh,$standard_period,$nonstandard_period,$max_elements,%whitelist,$dbname);
######################################################################################################
# $standard_period | elements which were added $standard_period seconds ago or ealier can be purged
######################################################################################################
# $max_elements | when number of elements in the database exceedes $max_elements, elements
# $nonstandard_period | which were added $nonstandard_period seconds ago or ealier can be purged
######################################################################################################
# %whitelist | hosts listed in %whitelist are never added to the database
######################################################################################################
# $dbname | data are stored in the "$dbname" database
######################################################################################################
$standard_period=5*24*60*60; #120 hours --- not tested yet but might work????
$nonstandard_period=24*60*60; #24 hours
$max_elements=2000;
%whitelist=(
"192.168.0.3"=>0,
"192.168.0.10"=>0,
"192.168.0.203"=>0
);
######################################################################################################
$dbname="C:/Apache228/logs/hackers.sqlite";
######################################################################################################
############## open lock file ##############
######################################################################################################
my $lock_file = 'C:/Apache228/tmp/ban-hackers.lock';
######################################################################################################
open LOCKFILE, "<$lock_file" or open LOCKFILE, ">>$lock_file" or warn "Cannot open $lock_file";
#$ip=$ENV{HTTP_X_FORWARDED_FOR};
$ip=$ENV{REMOTE_ADDR};
$dbh=&open_db;
#is script executed without arguments
if($#ARGV==-1 && $ip) {
# add actual IP to the database
# the script you execute must write something (anything) to stdout.
# If it doesn't ModSecurity will assume execution didn't work
# If you write something to stdout cron will email it to you
# so don't do that if running from cron and not Mod_Security
print "\t.\n";
######################################################################################################
open (LOGFILE, '>> C:/Apache228/logs/ban-hackers.log') or die "Can't open ban-hackers.log: $!";
######################################################################################################
select LOGFILE;
print "Ran: ", scalar(localtime), "\t$ip\n";
close LOGFILE;
# if connection was via proxy, address contains a list of client's IP
# and proxies' IP - hacker's IP will be IP of last proxy
my @ips=split(',',$ip); #the above addresses (elements of the list) are separated by ","
$ip=$ips[$#ips]; #hacker's IP is the last IP from the list
$ip =~s/^ *//; #Remove leading spaces:
# Addition for Rule Numbering when using "ipfw" rather than "iptables"
my ($sec,$rmin,$rhr,$mday,$mon,$year,$rday,$yday,$isdst) = localtime(time);
# $rday - day of the week [0-6] (Sun. is '0')
my $starter = 30000 + ($rday * 1440); # minutes in a day? 24 * 60 = 1440
my $rule = ((($rhr * 60) + $rmin) + $starter); # 30000 == "start_rule" and 40079 == "end_rule"
# there can be more than one rule with the same number in "ipfw" so its OK
flock(LOCKFILE, LOCK_EX);
if( !exists $whitelist{$ip} && !hacker_exists($dbh,$ip)){
&add_hacker_db($dbh,$ip,time,$rule); #add hacker's IP if it doesn't exists yet
#check if actual IP exists on the whitelist or in the database
# &add_hacker_db($dbh,$ip,time); #add hacker's IP if it doesn't exists yet
}
flock(LOCKFILE, LOCK_UN);
}
#when script is executed with the "purge" argument
elsif($#ARGV==0 && $ARGV[0] eq "purge"){
#purge the content of the database
flock(LOCKFILE, LOCK_EX);
&purge($dbh);
flock(LOCKFILE, LOCK_UN);
}
#when script is executed with the "add" argument
elsif($#ARGV==0 && $ARGV[0] eq "add"){
#add the content of a database to iptables
flock(LOCKFILE, LOCK_EX);
&add_hacker_iptables($dbh);
flock(LOCKFILE, LOCK_UN);
}
#when script is executed with the "list" argument
elsif($#ARGV==0 && $ARGV[0] eq "list"){
#list the content of the database
flock(LOCKFILE, LOCK_SH);
my $query = qq{select * from hackers};
my $sth= $dbh->prepare($query);
$sth->execute;
print "Hacker's IP\tWhen added\t\t\tRule\n",'-' x 53,"\n";
while (my (@data) = $sth->fetchrow_array) {
my $time = localtime($data[1]);
#print "$data[0]\t$time\n"; # Edit for "ipfw" use
print "$data[0]\t$time\t$data[2]\n";
}
flock(LOCKFILE, LOCK_UN);
}
$dbh->disconnect;
close LOCKFILE or die "Cannot close $lock_file";
###############################################################################
# opens a database and creates the "hackers" table if it wasn't created ealier
sub open_db{
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname","","") or die "Database connection not made: $DBI::errstr";
if (! table_exists( $dbh, "hackers")) { #if the "hackers" table doesn't exists
# my $create_query = qq{
# create table hackers (
# ip text unique,
# time integer not null
# )
# };
# addition/edit for "ipfw"
my $create_query = qq{create table hackers ( ip text unique, time integer not null, rule text not null)};
$dbh->do( $create_query ); #create it
}
return $dbh; #return a handler to the database
}
#####################################################
# add the IP and time stamp to the "hackers" database
sub add_hacker_db{
my $dbh = shift;
my $ip = shift;
my $time = shift;
my $rule = shift;
# my @fields = (qw(ip time));
my @fields = (qw(ip time rule));
my $fieldlist = join ", ", @fields;
my $field_placeholders = join ", ", map {'?'} @fields;
my $insert_query = qq{ INSERT INTO hackers ( $fieldlist ) VALUES ( $field_placeholders )};
my $sth= $dbh->prepare( $insert_query );
# $sth->execute($ip,$time);
$sth->execute($ip,$time,$rule);
}
#################################################
# add IPs stored in the database to the iptables
sub add_hacker_iptables{
# my $query = qq{select ip from hackers};
my $query = qq{select ip, rule from hackers};
my $sth= $dbh->prepare($query);
$sth->execute;
# addition for "ipfw"
# my @current_rules=`/sbin/iptables -L -n`;
######################################################################################################
my @current_rules=`C:/WINNT/system32/ipfw.exe -d list`;
######################################################################################################
while (my ($ip,$rule) = $sth->fetchrow_array) {
# don't create duplicate iptable rule
next if scalar grep {/$ip/} @current_rules; # need grep ??????
# addition for "ipfw"
#my $cmd ="/sbin/iptables -I INPUT -p tcp --dport 80 -s $ip -j DROP"; ipfw -q add $rule deny ip from $ip to me
######################################################################################################
my $cmd = "C:/WINNT/system32/ipfw.exe -q add $rule drop log ip from $ip to any via eth2"; # in via eth2
######################################################################################################
(system($cmd)==0) or warn "returned failure: $cmd";
}
}
###############################################################################
#check if the "ip" of hacker exists in database
sub hacker_exists{
my $dbh = shift;
my $ip = shift;
my $query = qq{select * from hackers where ip='$ip'};
my $sth= $dbh->prepare($query);
$sth->execute;
my($result) = $sth->fetchrow_array;
if($result){
return length($result);
}
else {
return 0;
}
}
###############################################################################
# remove hachers IP after selected time
sub purge{
my $dbh= shift;
my($time)=time;
# #it contains all the rules from 'iptables'
if($max_elements == 0 && $standard_period == 0){return;}
#if there is less than $max_elements in the database
if(count_hackers($dbh) <= $max_elements && $standard_period > 0){
$time -= $standard_period; #remove elements which are older than standard period
}
elsif($max_elements > 0) {
$time -= $nonstandard_period; #else remove elements which are older than non-standard period
}
my $query = qq{select ip,rule from hackers where time <= $time};
my $sth= $dbh->prepare($query);
$sth->execute;
my @ips =();
my @rules =();
while (my ($ip,$rule) = $sth->fetchrow_array) {
push @ips, $ip;
push @rules, $rule;
}
foreach $rule (@rules){ #remove "old" element from the database and from iptables
#my $cmd="/sbin/iptables -D INPUT -p tcp --dport 80 -s $ip -j DROP";
######################################################################################################
my $cmd="C:/WINNT/system32/ipfw.exe -q delete $rule";
######################################################################################################
(system($cmd)==0) or warn "returned failure: $cmd";
}
foreach $ip (@ips){ #remove "old" element from the database and from iptables
$dbh->do(qq{
delete from hackers
where ip='$ip'
} ) or die $dbh->errstr;
}
}
###############################################################################
#check if the table exists in the data base
# source: http://gmax.oltrelinux.com/dbirecipes.html
sub table_exists {
my $db = shift;
my $table = shift;
my @tables = $db->tables('','','','TABLE');
if (@tables) {
for (@tables) {
next unless $_;
return 1 if $_ eq $table
}
}
else {
eval {
local $db->{PrintError} = 0;
local $db->{RaiseError} = 1;
$db->do(qq{SELECT * FROM $table WHERE 1 = 0 });
};
return 1 unless $@;
}
return 0;
}
###############################################################################
# count the number of elements in the hackers table
sub count_hackers{
my $dbh= shift;
my $query=qq{SELECT COUNT(*) FROM hackers};
my $sth= $dbh->prepare($query);
$sth->execute;
my ($count) = $sth->fetchrow_array;
return $count;
}
|
REQUIREMENTS
1. Must have a cron such as "ntcron" installed
2. Requires unix tools "grep" accessable through commandline
3. Must have "wipfw" (stable) installed with allow any any - as default rule
4. Needs to have perl and specifically DBD::SQLite via ppm3 install DBD::SQLite (i used 1 as it came up with DBD::SQLite2 as well)
5. mod_security2.5.3 is tested after built with vc6
Here is rules for rules.conf file
Code: |
SecRule REQUEST_HEADERS:User-Agent "(?i:libwww-perl.*)$" "pass,exec:C:/Apache228/bin/ban-hackers.pl,msg:'Address has been blocked at firewall',severity:5,phase:1,id:'799914'"
#
### Based on Simplistic example to block an IP for
### 1 minute after requesting a page by tracking the IP.
#
### Initialize IP tracking
SecAction phase:1,pass,nolog,initcol:ip=%{REMOTE_ADDR}
SecAction phase:1,pass,nolog,setenv:aame=%{REMOTE_ADDR}-%{IP:blocker}
# Deny Further Access
SecRule IP:blocker "@eq 1" "t:none,phase:1,deny,status:410,msg:'IP Blocked',severity:'2',id:'799910',tag:'ACCESS_VIOLATION/BLOCK_LISTED'"
# FirstBlock and add to mod_security Blocklist (cover initial minute)
SecRule REQUEST_HEADERS:User-Agent "(?i:libwww-perl.*)$" "t:none,phase:1,setvar:IP.blocker=1,expirevar:IP.blocker=360,deny,status:410,msg:'IP Blocked - Added to block list',severity:'2',id:'799911',tag:'ACCESS_VIOLATION/BLOCK_LIST_ADD'"
|
in the "crontab" file
Code: |
# ban-hackers.pl
# Every minute check the database for new ip# to ban
* * * * * c:\perl\bin\perl.exe c:\apache228\bin\ban-hackers.pl add
# Every hour purge expired entries
0 * * * * c:\perl\bin\perl.exe c:\apache228\bin\ban-hackers.pl purge
|
Things I have missed in config I will update later, it works for me your milage may vary....
dave
EDIT: sorry the ban-hacker.log file needs to be created as the script doesn't create on first run! |
|
Back to top |
|
fingers
Joined: 21 Apr 2008 Posts: 7
|
Posted: Mon 28 Jul '08 8:46 Post subject: A couple of extra scripts |
|
|
to remove any false positives run either of these scripts and add the offending ip address to the whitelist array in the perl script...you need sqlite3.exe available....
Code: |
@echo off
SETLOCAL ENABLEEXTENSIONS
TITLE Remove SearchEngine from wIPFW Rule and SQLite Table
COLOR 2F
@ECHO ÿ ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
@ECHO ÿ º º
@ECHO ÿ º ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º
@ECHO ÿ º º Remove wIPFW Rule and SQLite Table Entry º º
@ECHO ÿ º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ º
@ECHO ÿ º By: Dave Arrowsmith º
@ECHO ÿ º º
@ECHO ÿ ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
PING -n 4 127.0.0.1 -w 500 >NUL
::REM --[ Remove Google etal from the Blocked database ]--
::REM --[ edit _searchtxt to equal the text you want to search for in nslookup ie google ]--
set _searchtxt=google
::REM --[ edit _database to match your perl script setting ]--
set _database=hackers.sqlite
::REM --[ edit the location to match your servers SQLite3 database folder ]--
set _datafldr=c:\Apache2.2.9\logs\
::REM --[ edit the location to match your .exe file installs http://sqlite.org/download.html ]--
set _sqlite_x=c:\Apache2.2.9\bin\sqlite3.exe
set _wipfw_ex=c:\Apache2.2.9\bin\ipfw.exe
::REM --[ Fixed Constants Don't Edit! ]--
set _deny=deny
set _name=Name
for /F "delims=" %%L in ('ipfw list ^| findstr /c:%_deny%') do call :sub_search_ipfw "%%L"
goto skip_subs
:sub_search_ipfw
set _next=%1
for /F "tokens=1-10* delims= " %%B in ("%_next%") do set _rule=%%B && set _ip=%%G
set _next=
if %_ip%!==to! goto exit_sub_search_ipfw
for /F "delims=" %%U in ('nslookup %_ip% ^| findstr /c:%_name%') do call :sub_search_nslookup "%%U"
:exit_sub_search_ipfw
set _ip=
set _rule=
exit /b
::
:sub_search_nslookup
set _str=%1
::--[ Strip the space characters from any parsed variable ]--::
set _stripstr=%_str: =%
set _str=
for /F "tokens=1-2* delims=:" %%Q in ("%_stripstr%") do set _ruledomain="%%R
for /F "delims=" %%J in ('echo %_ruledomain% ^| findstr /c:%_searchtxt%') do call :sub_match_found %%J
set _ruledomain=%_ruledomain:"=%
echo IP: %_ip% Domain: %_ruledomain%
set _ruledomain=
set _stripstr=
exit /b 0
::
:sub_match_found
::--[ Strip the double quote characters from _rule variable ]--::
set _rule=%_rule:"=%
::--[ Work with these Variables ]--::
::REM --[ Delete any %_searchtxt% wIPFW entries
call :sub_do_ipfw %_rule%
::REM --[ Delete any %_searchtxt% database entries
call :sub_do_sqlite %_ip%
::-[ Dont Need the Next lot-a-data ]--::
set _domain=%1
set _domain=%_domain:"=%
echo _domain: %_domain%
set _domain=
exit /b
::
::-[ ]--::
:sub_do_sqlite
set _iptxt=%1
echo _iptxt : %_iptxt%
%_sqlite_x% -line %_datafldr%%_database% "delete from hackers where ip='%_iptxt%';"
set _rule_set=
set _database=
set _datafldr=
set _sqlite_x=
set _iptxt=
exit /b 0
::
::-[ ]--::
:sub_do_ipfw
set _ruletxt=%1
echo _ruletxt: %_ruletxt%
%_wipfw_ex% -q delete %_ruletxt%
set _ruletxt=
exit /b 0
::REM--[ _sub_cleanup
:sub_do_varcleanup
for /f "usebackq tokens=1-2 delims==" %%Z in (`set _`) do set %%Z=
exit /b 0
:skip_subs
call :sub_do_varcleanup
pause
ENDLOCAL
exit
|
or
Code: |
@echo off
SETLOCAL ENABLEEXTENSIONS
::
set _database=hackers.sqlite
set _datafldr=c:\Apache2.2.9\logs\
::REM --[ http://sqlite.org/download.html ]--
set _sqlite_x=c:\Apache2.2.9\bin\sqlite3.exe
::REM use...
::REM YES or NO - (use NO for Automatic removal)
set _useapp=NO
set _app="C:\Installing\sqlitebrowser-1.3-win\SQLite Database Browser.exe"
set _dbase="C:\Apache2.2.9\logs\hackers.sqlite"
::
TITLE Remove wIPFW Rule from Table
COLOR 2F
@ECHO ÿ ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
@ECHO ÿ º º
@ECHO ÿ º ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º
@ECHO ÿ º º Remove wIPFW Rule from Table º º
@ECHO ÿ º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ º
@ECHO ÿ º By: Dave Arrowsmith º
@ECHO ÿ º º
@ECHO ÿ ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
PING -n 4 127.0.0.1 -w 500 >NUL
:tryagain
cls
ipfw list
@echo.
set /P _rule=Type the Number of the Rule to delete then press ^<enter^>:---
if '%_rule%'=='' goto tryagain
::--[ if '%_rule%'=='' goto tryagain ]--::
for /F "delims=" %%a in ('ipfw list ^| findstr /c:%_rule%') do set _var=%%a
for /F "tokens=1* delims= " %%A in ("%_var%") do set _res=%%A
if not "%_rule%"=="%_res%" goto failure
ipfw.exe -q delete %_rule%
@echo.
@ECHO ÿ Successfully removed Rule - %_rule% - from the wIPFW drop tables
@echo.
@ECHO ÿ ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
@ECHO ÿ º º
@ECHO ÿ º Don't Forget to delete it from the SQLite Database too!!!!!! º
@ECHO ÿ º º
@ECHO ÿ ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
@echo.
PING -n 4 127.0.0.1 -w 500 >NUL
if %_useapp%!==NO! call sub_sqlite_purge %_rule%
::REM OR...
if %_useapp%!==YES! start "" %_app% %_dbase%
goto success
exit
::REM --[ Sub-Program Section ]--
:sub_sqlite_purge
::REM --[ call sub_sqlite_purge %_rule% ]--
set _deleteme=%1
%_sqlite_x% -line %_datafldr%%_database% "delete from hackers where rule='%_deleteme%';"
set _rule_set=
set _database=
set _datafldr=
set _sqlite_x=
exit /b 0
::REM--[ _sub_cleanup
:sub_varcleanup
for /f "usebackq tokens=1-2 delims==" %%Z in (`set _`) do set %%Z=
exit /b 0
:failure
cls
@echo.
@echo ÿ ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
@echo.
@echo ÿ That rule, %_rule%, wasn't found! Try Again?
@echo.
@echo ÿ ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
@echo.
@echo.
@echo.
@echo.
pause
:success
call :sub_varcleanup
ENDLOCAL
exit
|
hope all the characters are displayed correctly....
dave |
|
Back to top |
|
|
|
|
|
|