逆向怎么玩 - 动态调试jetBrains CLion实录 - foreach_break - 博客园

mikel阅读(1273)

来源: 逆向怎么玩 – 动态调试jetBrains CLion实录 – foreach_break – 博客园

声明

CLion程序版权为jetBrains所有、注册码授权为jetBrains及其付费用户所有,本篇只从兴趣出发,研究其程序运行原理。

  • 不会释出任何完整的源代码.
  • 网上查了下,已有注册机,所以想要key的同学不要找我:p

背景

在上篇:CLion注册码算法逆向分析实录

我们通过结合jdb、jd-gui等工具,静态分析被混淆过的CLion的clion.jar中的class信息,顺利拿到了CLion的注册码算法.

但是,如果能在动态调试中分析代码路径,拿注册码并推算法不是更愉快么?
本篇将从动态调试的角度展开逆向之旅,作为对上篇的一个补充。

本篇用到的关键技术和工具:

  • java -verbose
  • HotSpot™ Serviceability Agent
  • jetBrains intellij IDEA 14.3
  • jetBrains CLion 1.0.4
  • jd-gui 1.2
  • jinfo

动态调试的困难

因为没有源代码,而CLion的class经过混淆,且有很多运行时生成的class,所以无法直接通过简单地使用类似jd-gui之类的工具来得到java文件。

如果仅仅是名称和控制流混淆,其实还是比较简单的情况,不是太变态的情况下,jd-gui可以拿到java代码,如果混淆的很厉害,一般也有字节码可以看,所以需要我们对字节码或混淆代码的阅读感觉比较熟练即可。

如果是上面的相对简单的情况,我们可以有耐心地重建或者修补反编译而来的java代码,以达到调试的目的。

CLion的情况不同,它还有一些运行时生成的类,再加上混淆,使得我们很难仅仅通过反编译来完成动态调试的准备。


获取入口函数所在的类名

办法总比困难多,让我们开始准备动态调试吧!

通过上一篇博文的分析,我们已经熟悉了CLion程序启动的一些代码路径,首先要找到程序的入口函数main,并重建它。怎么找呢?

  • 方法1:通过启动脚本来找

可以通过查看$CLION_HOME/bin下的clion.sh来看启动参数:

133 MAIN_CLASS_NAME="$CL_MAIN_CLASS_NAME"
134 if [ -z "$MAIN_CLASS_NAME" ]; then
	  #注意这里
135   MAIN_CLASS_NAME="com.intellij.idea.Main"
136 fi
...
176 LD_LIBRARY_PATH="$IDE_BIN_HOME:$LD_LIBRARY_PATH" "$JDK/bin/java" \
177   $AGENT \
178   "-Xbootclasspath/a:$IDE_HOME/lib/boot.jar" \
179   -classpath "$CLASSPATH" \
180   $VM_OPTIONS "-Djb.vmOptionsFile=$VM_OPTIONS_FILES_USED" \
181   "-XX:ErrorFile=$HOME/java_error_in_CL_%p.log" \
182   -Djb.restart.code=88 -Didea.paths.selector=clion10 \
183   $IDE_PROPERTIES_PROPERTY \
184   $IDE_JVM_ARGS \
185   $REQUIRED_JVM_ARGS \
      #以及这里
186   $MAIN_CLASS_NAME \
187   "$@"
188 EC=$?
  • 方法2:通过jinfo来获取

也可以让CLion先跑起来,通过jinfo来获取,首先通过jpsps -ef | grep clion来确认CLion的pid

[haoran@localhost Tools]$ jps
27120 Jps
4001 Main
26953 Main
16911 Launcher

接着输入jinfo pid,这里是jinfo 26953

[haoran@localhost Tools]$ jinfo 26953
Attaching to process ID 26953, please wait...
Error attaching to process: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 25.45-b02. Target VM is 25.40-b25
sun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 25.45-b02. Target VM is 25.40-b25
	at sun.jvm.hotspot.HotSpotAgent.setupVM(HotSpotAgent.java:435)
	at sun.jvm.hotspot.HotSpotAgent.go(HotSpotAgent.java:305)
	at sun.jvm.hotspot.HotSpotAgent.attach(HotSpotAgent.java:140)
	at sun.jvm.hotspot.tools.Tool.start(Tool.java:185)
	at sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)
	at sun.jvm.hotspot.tools.JInfo.main(JInfo.java:138)

发现因为jre/jvm的版本不匹配,出现了异常,怎么解决呢?
clion.sh入手,看看它如何指定jvm

这里写图片描述

可以发现,$IDE_HOME意即CLion安装的路径比$JAVA_HOME搜索的顺序更靠前,我们调整这个顺序即可避免jre/jvm版本不匹配的问题。

调整后,再次利用jinfo pid来查看,得到如下信息:

这里写图片描述

之所以列举jre/jvm版本不匹配的异常问题,以及通过jinfo来获取程序入口函数所在类的方式,是为后续我们通过SA来dump运行时的class及修复java文件扫清障碍。


新建入口类

我们已经得到main函数所在的类名为com.intellij.idea.Main,但是通过分析,发现其不在clion.jar中,那么它在哪里?

我们通过在CLion启动参数中加入-verbose,并将结果重定向到文件中,来分析这个类所在的jar。

如下所示:

这里写图片描述

接下来,通过jd-gui来反编译bootstrap.jar/com/intellij/idea/Main.class,并将其java代码导入到我们新建的同名java文件中:

这里写图片描述


修复入口类

这样的java代码是无法通过编译的,而且因为很多缺失的类都是很重要的依赖,所以无法通过简单的屏蔽来让代码跑起来。

那我们开始修复这些缺失的类,怎么修复呢?

我们可以使用HotSpot™ Serviceability Agent (SA)提供的能力,获取运行时的class。当然,获取运行时的class不只这一种方式。

说干就干,classFilter:

这里写图片描述


编译好这个classFilter,按下面的步骤来运行:

  1. 运行CLion.
  2. 找到CLion的pid.
  3. 启动如下命令:

java -cp $JAVA_HOME/lib/sa-jdi.jar:. \
	 -Dsun.jvm.hotspot.tools.jcore.filter=$filterName \
	 -Dsun.jvm.hotspot.tools.jcore.outputDir=$dumpedClassOutputDir \
	 sun.jvm.hotspot.tools.jcore.ClassDump $clion_pid

# $filterName  :我们自定义的classFilter
# $dumpedClassOutputDir : 存放dump出的class文件的目录
# $clion_pid :CLion进程pid.

看下我们dump出的classes:

这里写图片描述

到这一步,已经成功了一大半,接下来,按照你喜欢的方式将这些classes加入classPath吧!


修复ClassPath

还在等什么,赶紧点run吧:

这里写图片描述

嗯,果不其然,很多类还是缺失,对于运行中生成的类,按上面的方法来找,对于已经在jar中的类,赶紧找找classPath还有什么吧。

还记得上面的jinfo吧,祭出:

这里写图片描述

将这些加入ClassPath中。


修复资源、运行时参数、及JVM的options

程序已经越来越接近跑起来的状态,还有一些细碎,奔跑吧骚年!

Q. 此刻有没有一种,买来风扇,涂上硅胶,扣定开关的感觉?
A. 要的就是这种能够DIY的工程师感觉嘛~^^

你会发现,后续的运行中,还会出现许多异常,没有关系,通过分析,就知道还有一些东西没有修复,包括:

  • 资源/Resources
  • 运行时参数
  • vm options

其中CLion的vm options我们依然通过jinfo方式获取:

-Xss2m -Xms256m -Xmx768m -XX:MaxPermSize=250m \
-XX:ReservedCodeCacheSize=96m -XX:+UseConcMarkSweepGC \

-XX:ErrorFile=/home/haoran/java_error_in_CL_%p.log \
-Djb.restart.code=88 -Didea.paths.selector=clion10 \
-Didea.platform.prefix=CLion \
-Didea.no.jre.check=true


让程序动起来!

做完了上面细碎的功夫,来看看我们的成果:

  • 华丽丽的Stack Frames!

这里写图片描述


  • 华丽丽的Locals!

这里写图片描述


  • 华丽丽的注册码算法!
    这里写图片描述

这里写图片描述


这里写图片描述


结语

什么?没有动态调试过程?

有意研究注册码算法的同学,请参考上篇博文:CLion注册码算法逆向分析实录.但是不要做坏事哦 :]

我觉得上面的几个华丽丽的东西已经足够你

  • step in/over/out
  • evaluate expressions
  • stack frame in/out

羞涩ing : 撰文不易,若觉得对你有帮助或者博你一笑的,点个推荐吧 :]

【版权所有@foreach_break】 【博客地址 http://www.cnblogs.com/foreach-break】 可以转载,但必须注明出处并保持博客超链接

用“WebKit.NET”封装内核浏览器

mikel阅读(1586)

正 文:

由于Google Chrome采用了WebKit内核,由此使得WebKit内核浏览器的人气迅速攀升。对于庞大的webkit开源程序,普通 程序员一般无需接触。通过WebKit.NET,我们也可以开发一些简单的浏览器。WebKit.NET 是一个 C# 的组件封装了 WebKit 浏 览器引擎,通过它可以在 .NET 应用中简单的使用 WebKit 浏览器引擎。    使用方法也很简单,首先到 http://webkitdotnet.sourceforge.net/ 下载webkit.net编译好的dll文件(Win32 Binary ),目前最新的是 2010-08-28 发布的 0.5 版本。    然 后把WebKitBrowser控件拉进工具箱:VS工具–》选择工具项–》.NET Framework组件–》浏览–》选择 “WebKitBrowser.dll”,这时WebKitBrowser就应该出现在左侧的公共控件里了。使用的时候直接拖曳到窗口里使用即 可,WebKitBrowser的使用方法和IE的内核webbrowser类似。    WebKitBrowser简单用法:1、访问某个网页。

webKitBrowser1.Navigate(“http://www.piaoyi.org”);

2、加载网页完成时。

 private void webKitBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
textBox1.Text = webKitBrowser1.Url.ToString ();
}

 

WebKit.NET内核浏览器

需要注意的问题:
1、webkit目前只有32位版本的,因此如果你是64位windows系统,将无法正常使用。为了兼容,需要将调试平台的cpu选择为 X86(vs默认是 any cpu)。2、需要把从网上下载下来的一大堆dll文件放在输出目录里,和 最终的可执行文件 sample.exe 放在一个目录里,不能放在其他文件夹或子目录,否则 WebKit 出错。3、如果出错,检查引用里是否引用了 WebKit.Interop and WebKitBrowser.     飘易认为的 WebKit.net 封装的 bug。1、打开新窗口时的bug。
在 事 件 private void webKitBrowser1_NewWindowCreated(object sender, NewWindowCreatedEventArgs args)  和 private void webKitBrowser1_NewWindowRequest(object sender, NewWindowRequestEventArgs args) 里 都无法正常获取新的 url 。

        private void webKitBrowser1_NewWindowCreated(object sender, NewWindowCreatedEventArgs args)
{
webKitBrowser1 = args.WebKitBrowser;
}        private void webKitBrowser1_NewWindowRequest(object sender, NewWindowRequestEventArgs args)
{
MessageBox.Show(args.Url);
}

2、DOM模型,如 webKitBrowser1.DocumentText 不好利用。    当然,以上都是飘易个人之看法,不免贻笑大方。可以参考另外一种 C# GeckoFX内核浏览器

c#WebBrowser进阶 - 派大星啊 - 博客园

mikel阅读(939)

来源: c#WebBrowser进阶 – 派大星啊 – 博客园

WebBrowser的基本功能就是访问网页,但是由于它本身就不在主线程上面,所以程序判断它什么时候加载完成了,比较麻烦。为此我集合从网上找到的内容,做了一个例子。

其中包括了给WebBrowser设置cookies,点击WebBrowser中的button等功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
   [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
   public static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData)
   private delegate void invokeDelegate();
  public void bk()
        {
                     
            string url = "http://*******"//任意网址
            //添加cookies
            for (int i = 0; i < cookies.Count; i++)
            {
                Cookie c = cookies[i];
                InternetSetCookie(url, c.Name, c.Value);
            }
            webBrowser2.Navigate(url);
            webBrowser2.ScriptErrorsSuppressed = true;
            while (true)
            {
                Application.DoEvents();
                if (webBrowser2.ReadyState != WebBrowserReadyState.Complete)
                {
                    break;
                }
            }
        
            invokeDelegate del = new invokeDelegate(StartMethod);
            IAsyncResult ir = del.BeginInvoke(AddComplete, null);
        }   
/// <summary>
/// 委托异步
/// </summary>
/// <param name="result"></param>
private void AddComplete(IAsyncResult result)
{
invokeDelegate handler = (invokeDelegate)((AsyncResult)result).AsyncDelegate;
handler.EndInvoke(result);
}

 

上面的代码是在webBrowser2中加载网页,使用了委托异步的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private void StartMethod()
       {
          
           Thread.Sleep(7000);
       
           this.Invoke(new Action(() =>
           {
               HtmlDocument cd = webBrowser2.Document;
               string doc = webBrowser2.DocumentText;          
               int count = 0;
               HtmlElementCollection dhl1 = cd.GetElementsByTagName("input");//GetElementsByTagName得到的是点击的标记元素名称
               foreach (HtmlElement item in dhl1)
               {
                   string elemName = item.GetAttribute("name");
                   if (elemName != null || elemName.Length > 0)
                   {
                       if (elemName == "btnclick")
                       {
                           item.InvokeMember("click");
                       }                   
                   }
               }
           }));
    
        
       }

开始加入Thread.Sleep(7000);是为了给webBrowser2加载页面的时间,7s足够页面加载完成。然后在获取页面的内容,并找到btnclick进行点击。

最后贴出从txt中获取cookies的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static CookieCollection getCookies(string path)
       {
           string cook = ReadTxt(path).Trim();
           CookieCollection cookies = new CookieCollection();
           string[] cookstr = cook.Split(';');
           foreach (string str in cookstr)
           {
               string[] cookieNameValue = str.Split('=');
               cookieNameValue[1] = cookieNameValue[1].Trim().ToString().Replace(",", "%2C");
               Cookie ck = new Cookie(cookieNameValue[0].Trim().ToString(), cookieNameValue[1].Trim().ToString());
               ck.Domain = "*******";//Host地址,可从浏览器上查看
               cookies.Add(ck);
           }
           return cookies;
       }

这样就可以实现自动加载某个网页并点击页面上的按钮了。

当站长遭遇作弊

mikel阅读(929)

每个体验站长都希望会员踏踏实实的做任务赚钱,毕竟辛苦搭建的网站,努力推广来的会员,真心不容易,很希望那些会员能够从网上赚到钱,并不吝惜那点签到和推广的费用,可偏偏就有人偷奸耍滑喜欢作弊。

结果可想而知,损人不利己,为什么这么说?首先,自己的账号被查出来,直接封号,收入没了,辛苦努力刷量作弊的时间荒废了,最严重的是直接支付宝号列入黑名单,直接永久封禁。损人就更不用说了,联盟发现网站作弊,直接将刷量扣除,然后将被刷量的产品下架,这下本来大家可以都赚钱的产品没了,站长很苦恼,会员也很苦恼。

一个网站建起来不容易,那些刷量的太短视了,国内网赚环境为什么一直是乌烟瘴气,不如国外规范,究其根本原因就是因为大家总是不守规矩,作弊骗人等等,搞得谈网赚色变,新手不敢做,老手人人自危,结果越做圈子越窄,项目越少,大家都饿死了。

好的环境还要有好的人维护和爱惜才能良性发展。何苦穷人为难穷人?!

C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理 - 伍华聪 - 博客园

mikel阅读(755)

来源: C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理 – 伍华聪 – 博客园

在上篇随笔《C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理》介绍了通讯录的部门的相关操作管理,通讯录管理包括部门管理、成员管理、标签管理三个部分,本篇主要介绍成员的管理操作,包括创建、删除、更新、获取、获取部门成员几个操作要点。

1、成员的创建操作

为了方便,我们可以创建一个部门组织结构,这是开发的前提,因为我们通讯录管理,也是基于一个组织机构下的,如上篇介绍的组织结构层次一样。我这里创建一个广州爱奇迪的根结构,然后在其中在创建一些组织机构,如下图所示。

在后台可以通过功能操作添加人员,本篇主要介绍如何调用微信企业号API进行人员管理的操作。

创建人员的API定义如下所示。

  • 请求说明

Https请求方式: POST

https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token=ACCESS_TOKEN

请求包结构体为:

{
   "userid": "zhangsan",
   "name": "张三",
   "department": [1, 2],
   "position": "产品经理",
   "mobile": "15913215421",
   "gender": 1,
   "tel": "62394",
   "email": "zhangsan@gzdev.com",
   "weixinid": "zhangsan4dev"
}
  • 参数说明
参数 必须 说明
access_token 调用接口凭证
userid 员工UserID。对应管理端的帐号,企业内必须唯一。长度为1~64个字符
name 成员名称。长度为1~64个字符
department 成员所属部门id列表。注意,每个部门的直属员工上限为1000个
position 职位信息。长度为0~64个字符
mobile 手机号码。企业内必须唯一,mobile/weixinid/email三者不能同时为空
gender 性别。gender=0表示男,=1表示女。默认gender=0
tel 办公电话。长度为0~64个字符
email 邮箱。长度为0~64个字符。企业内必须唯一
weixinid 微信号。企业内必须唯一
  • 权限说明

管理员须拥有“操作通讯录”的接口权限,以及指定部门的管理权限。

  • 返回结果
{
   "errcode": 0,
   "errmsg": "created"
}

我们在C#里面,需要定义对应给的接口,然后根据需要构造对应的传递实体信息。

这里我把人员管理的接口全部定义好,接口定义如下所示。

复制代码
        #region 部门成员管理
        /// <summary>
        /// 创建成员
        /// </summary>
        CommonResult CreateUser(string accessToken, CorpUserJson user);

        /// <summary>
        /// 更新成员
        /// </summary>
        CommonResult UpdateUser(string accessToken, CorpUserUpdateJson user);

        /// <summary>
        /// 删除成员
        /// </summary>
        CommonResult DeleteUser(string accessToken, string userid);

        /// <summary>
        /// 根据成员id获取成员信息
        /// </summary>
        CorpUserGetJson GetUser(string accessToken, string userid);

        /// <summary>
        /// 获取部门成员
        /// </summary>
        CorpUserListJson GetDeptUser(string accessToken, int department_id, int fetch_child = 0, int status = 0);
        #endregion
复制代码

然后根据信息定义,创建一个承载人员信息的CorpUserJson实体对象,创建人员的实现操作代码如下所示。

复制代码
        /// <summary>
        /// 创建成员
        /// </summary>
        public CommonResult CreateUser(string accessToken, CorpUserJson user)
        {
            string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token={0}";
            var data = new
            {
                userid = user.userid,
                name = user.name,
                department = user.department,
                position = user.position,
                mobile = user.mobile,
                gender = user.gender,
                tel = user.tel,
                email = user.email,
                weixinid = user.weixinid
            };
            var url = string.Format(urlFormat, accessToken);
            var postData = data.ToJson();

            return Helper.GetCorpExecuteResult(url, postData);
        }
复制代码

 

2、成员的更新操作

成员的数据更新和创建操作类似,它的企业号定义如下所示。

  • 请求说明

Https请求方式: POST

https://qyapi.weixin.qq.com/cgi-bin/user/update?access_token=ACCESS_TOKEN

请求包示例如下(如果非必须的字段未指定,则不更新该字段之前的设置值):

{
   "userid": "zhangsan",
   "name": "李四",
   "department": [1],
   "position": "后台工程师",
   "mobile": "15913215421",
   "gender": 1,
   "tel": "62394",
   "email": "zhangsan@gzdev.com",
   "weixinid": "lisifordev",
   "enable": 1
}

由于它的操作数据类似,因此它的实现代码也差不多,如下所示就是。

复制代码
        /// <summary>
        /// 更新成员
        /// </summary>
        public CommonResult UpdateUser(string accessToken, CorpUserUpdateJson user)
        {
            string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/user/update?access_token={0}";
            //string postData = user.ToJson();
            var data = new
            {
                userid = user.userid,
                name = user.name,
                department = user.department,
                position = user.position,
                mobile = user.mobile,
                gender = user.gender,
                tel = user.tel,
                email = user.email,
                weixinid = user.weixinid,
                enable = user.enable
            };
            var url = string.Format(urlFormat, accessToken);
            var postData = data.ToJson();

            return Helper.GetCorpExecuteResult(url, postData);
        }
复制代码

 

3、成员的删除、成员的获取、部门成员的获取操作

这些操作和上面的类似,不在赘述,主要就是根据需要定义他们对应的返回数据信息,然后解析Json数据即可转换为对应的实体。

1)删除人员的定义如下:

  • 请求说明

Https请求方式: GET

https://qyapi.weixin.qq.com/cgi-bin/user/delete?access_token=ACCESS_TOKEN&userid=lisi

  • 参数说明
参数 必须 说明
access_token 调用接口凭证
userid 员工UserID。对应管理端的帐号
  • 返回结果
{
   "errcode": 0,
   "errmsg": "deleted"
}

2)成员的获取定义如下:

  • 请求说明

Https请求方式: GET

https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=lisi

  • 参数说明
参数 必须 说明
access_token 调用接口凭证
userid 员工UserID
  • 返回结果
{
   "errcode": 0,
   "errmsg": "ok",
   "userid": "zhangsan",
   "name": "李四",
   "department": [1, 2],
   "position": "后台工程师",
   "mobile": "15913215421",
   "gender": 1,
   "tel": "62394",
   "email": "zhangsan@gzdev.com",
   "weixinid": "lisifordev",  
   "avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
   "status": 1
}

3)部门成员的获取定义如下:

  • 请求说明

Https请求方式: GET

https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token=ACCESS_TOKEN&department_id=1&fetch_child=0&status=0

  • 参数说明
参数 必须 说明
access_token 调用接口凭证
department_id 获取的部门id
fetch_child 1/0:是否递归获取子部门下面的成员
status 0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
  • 权限说明

管理员须拥有’获取部门成员’的接口权限,以及指定部门的查看权限。

  • 返回结果
{
   "errcode": 0,
   "errmsg": "ok",
   "userlist": [
           {
                  "userid": "zhangsan",
                  "name": "李四"
           }
     ]
}

这个返回值我们定义一个实体对象用来存储数据即可。

复制代码
    /// <summary>
    /// 获取部门成员返回的数据
    /// </summary>
    public class CorpUserListJson : BaseJsonResult
    {
        public CorpUserListJson()
        {
            this.userlist = new List<CorpUserSimpleJson>();
        }

        /// <summary>
        /// 返回的错误消息
        /// </summary>
        public CorpReturnCode errcode { get; set; }

        /// <summary>
        /// 对返回码的文本描述内容
        /// </summary>
        public string errmsg { get; set; }

        /// <summary>
        /// 成员列表
        /// </summary>
        public List<CorpUserSimpleJson> userlist { get; set; }
    }
复制代码

 

7、综合例子调用代码

上面介绍了一些企业号的接口定义和我对API的C#封装接口和部分实现代码,实现了功能后,我们就可以在代码中对它进行测试,确信是否正常使用。

复制代码
        /// <summary>
        /// 人员管理综合性操作(创建、修改、获取信息、删除)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCorpUser_Click(object sender, EventArgs e)
        {
            CorpUserJson user = new CorpUserJson();
            user.userid = "test";
            user.name ="测试用户";
            user.department = new List<int>(){2};
            user.email = "test@163.com";

            ICorpAddressBookApi bll = new CorpAddressBookApi();
            CommonResult result = bll.CreateUser(token, user);
            if (result != null)
            {
                Console.WriteLine("创建成员:{0} {1} {2}", user.name, (result.Success ? "成功" : "失败"), result.ErrorMessage);

                string name = "修改测试";
                user.name = name;
                CorpUserUpdateJson userUpdate = new CorpUserUpdateJson(user);
                result = bll.UpdateUser(token, userUpdate);
                if (result != null)
                {
                    Console.WriteLine("修改名称:{0} {1} {2}", name, (result.Success ? "成功" : "失败"), result.ErrorMessage);
                }

                CorpUserGetJson userGet = bll.GetUser(token, user.userid);
                if (userGet != null)
                {
                    Console.WriteLine("成员名称:{0} ({1} {2})", userGet.name, user.userid, user.email);
                }

                result = bll.DeleteUser(token, user.userid);
                if (result != null)
                {
                    Console.WriteLine("删除成员:{0} {1} {2}", name, (result.Success ? "成功" : "失败"), result.ErrorMessage);
                }
            }
        }
复制代码

获取部门人员的操作代码如下所示。

复制代码
        /// <summary>
        /// 获取部门人员
        /// </summary>
        private void btnCorpUserList_Click(object sender, EventArgs e)
        {
            int deptId = 1;
            ICorpAddressBookApi bll = new CorpAddressBookApi();
            CorpUserListJson result = bll.GetDeptUser(token, deptId);
            if (result != null)
            {
                foreach(CorpUserSimpleJson item in result.userlist)
                {
                    Console.WriteLine("成员名称:{0} {1}", item.name, item.userid);
                }
            }
        }
复制代码

 

人员的管理,相对来说比较简单,主要是在一定的部门下创建人员,然后也可以给标签增加相应的人员,基本上就是这些了,不过一定需要确保有相应的权限进行操作。

如果对这个《C#开发微信门户及应用》系列感兴趣,可以关注我的其他文章,系列随笔如下所示:

C#开发微信门户及应用(25)-微信企业号的客户端管理功能

C#开发微信门户及应用(24)-微信小店货架信息管理

C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试

C#开发微信门户及应用(22)-微信小店的开发和使用

C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密

C#开发微信门户及应用(20)-微信企业号的菜单管理

C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)

C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理

C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理

C#开发微信门户及应用(16)-微信企业号的配置和使用

C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能

C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据

C#开发微信门户及应用(13)-使用地理位置扩展相关应用

C#开发微信门户及应用(12)-使用语音处理

C#开发微信门户及应用(11)–微信菜单的多种表现方式介绍

C#开发微信门户及应用(10)–在管理系统中同步微信用户分组信息

C#开发微信门户及应用(9)-微信门户菜单管理及提交到微信服务器

C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍

C#开发微信门户及应用(7)-微信多客服功能及开发集成

C#开发微信门户及应用(6)–微信门户菜单的管理操作

C#开发微信门户及应用(5)–用户分组信息管理

C#开发微信门户及应用(4)–关注用户列表及详细信息管理

C#开发微信门户及应用(3)–文本消息和图文消息的应答

C#开发微信门户及应用(2)–微信消息的处理和应答

C#开发微信门户及应用(1)–开始使用微信接口

 

主要研究技术:代码生成工具、Visio二次开发、客户关系管理软件、病人资料管理软件、送水管理软件等共享软件开发
专注于Winform开发框架Web开发框架、WCF开发框架、微信门户开发框架的研究及应用。
转载请注明出处:
撰写人:伍华聪  http://www.iqidi.com

资本运作 钱生钱的奥秘

mikel阅读(1555)

很多人都在给钱打工,每天上班下班就为了工资疲于奔命,开个买卖赚辛苦钱,也是在为钱打动。

有些人却是让钱在为自己打工,让钱生钱的投资计划,投资债权,股票等能够增值的理财产品等等。

互联网上也有很多这样的人,比如蔡文胜早起投资域名,基本上好的域名都被他买了,比如weibo.com之类的都增值了不下千倍,让他一下子有了资本投资美图秀秀等等有潜力的公司,彻底的财务自由。

很多职业经理人也走得是先打工,赚足了钱投资让钱生钱的路子,最终财务自由。

我们这些老百姓如何才能财务自由?!

其实很简单,从点滴做起,买入资产,少买入负债!

就这两句很多人做不到,但是要分清什么是资产,什么是负债,也简单,就是那些从你兜里使劲往外拽钱出去的都是负债,比如汽车,如果你只是个上班族,那么你就购买了负债,因为油费要花钱,保养要花钱等等,如果那些能够让钱不断流入你口袋的东西就是资产,比如你买的国债,股票等等尽管投资有风险,但是选择好的投资理财产品,会让你的口袋越来越鼓,多购入这些产品,让钱生钱才能最终靠这些产生的额外价值购买你想要的汽车洋房。

这是老百姓的资本运作,有钱人就更简单了,做天使可以赚钱丰厚的回报,但是同样承担大的风险,一般都是运作盈利的公司上市套现,这才是资本运作。

解决方法:An error occurred on the server when processing the URL. Please contact the system administrato-杰诚网络工作室

mikel阅读(746)

解决方法:AnerroroccurredontheserverwhenprocessingtheURL.Pleasecontactthesystemadministrator在WINDOWS7或SERVER2008上安装了IIS7.5,调试ASP程序时出现以下错误:AnerroroccurredontheserverwhenprocessingtheURL.Pleasecontactthesyst

来源: 解决方法:An error occurred on the server when processing the URL. Please contact the system administrato-杰诚网络工作室

解决方法:An error occurred on the server when processing the URL. Please contact the system administrator

在WINDOWS7或SERVER2008上安装了IIS7.5,调试ASP程序时出现以下错误:
An error occurred on the server when processing the URL. Please contact the system administrator
解决方法如下:
   设置方法一:
以管理员身份运行CMD,将目录定位到%windir%\system32\inetsrv\,然后执行appcmd set config -section:asp -scriptErrorSentToBrowser:true。

%windir%\system32\inetsrv\appcmd set config -section:asp -scriptErrorSentToBrowser:true
   设置方法二:
打开IIS7的asp设置,展开“调试属性”选项,“将错误发送到浏览器”这项默认的是False,改为True,然后点右侧的应用!如图所示:

解决方法:An error occurred on the server when processing the URL. Please contact the system administrator - 榕river - 很长的春天夏天

通过以上设置后,再从浏览时打开出错ASP页面时就能看到页面出错的详细信息,方使调试。如果是公开的Web服务器建议不要打开此选项,以防出错信息被他人利用。

ASP---HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容 - lc448986375的专栏 - 博客频道 - CSDN.NET

mikel阅读(701)

来源: ASP—HTTP 错误 403.14 – Forbidden Web 服务器被配置为不列出此目录的内容 – lc448986375的专栏 – 博客频道 – CSDN.NET

今天在网上看到个免费的企业网站系统(新秀),安装后遇到个问题,不管点击什么链接都会出现:

HTTP 错误 403.14 – Forbidden Web 服务器被配置为不列出此目录的内容

的错误,根据上面的错误提示:

·  如果不希望启用目录浏览,请确保配置了默认文档并且该文件存在。

·  使用 IIS 管理器启用目录浏览。

  1. 打开 IIS 管理器。
  2. 在“功能”视图中,双击“目录浏览”。
  3. 在“目录浏览”页上,在“操作”窗格中单击“启用”。

·  确认站点或应用程序配置文件中的

修改后不提示这个错误了,但是看到的是文件夹里面的内容,我是希望能演示网站内容,又查了很多资料发现只要设置好默认文档就就可以了具体操作如下:

我的电脑室win7 64位系统:

控制面板》系统和安全》管理工具Internet信息服务(IIS)管理器

双击“默认文档”,打开后点击右边的“添加”,添加自己项目的默认的文档就可以,我的是”index.asp”,添加后就可以正常运行了

iOS手机应用开发原型模板及开发流程 - jiangys - 博客园

mikel阅读(964)

来源: iOS手机应用开发原型模板及开发流程 – jiangys – 博客园

在开始做一个项目的时候,究竟需要准备些什么前期工作呢,在外包公司中,又是一个怎么样的开发步骤呢?下面,按照我的理解,说一下。

项目流程图

看上图,从左往右,如果我们仅是一名开发工程师,只需要关心上图中“开发工程师”的职责。

当然,开发项目前,大部分工作是需要“项目经理”和“产品经理”去完成的,比如,分析、消化客户的需求,形成文档及原型图、总框架图及流程图等。

APP开发流程图:

通过上面的图片,相信大家对一个项目的开发流程已经有一个大致的了解了。在开发项目前,最重要的一步是要是产品原型文档。产品原型文档及产品原型 图,一般是由产品经理及UI设计师来实现。如果我们不愿意看到需求经常被变更,产品原型文档及原型图就变得非常的重要。我们把最终的功能点及展示效果都描 述清楚,并让客户签字再开发,这样就会大大的提高开发的效率。

产品原型

产品原型设计,一般都是用 axure 来设计,是一个页面效果版。如下面的某公司的产品原型效果图:

当前,你也可以设计得像“小说App结构图”这样:

附:商户终端APP产品原型模板(axure):点击下载