Postgresql数组

PostgreSQL允许将表的列定义为可变长度的多维数组。 可以创建任何内置或用户定义的基类型,枚举类型或复合类型的数组。

 Qrcodes    integer[];

初始化:要将数组值写为文字常量,请将元素值括在花括号中并用逗号分隔。 您可以在任何元素值周围加上双引号,如果它包含逗号或花括号,则必须这样做。 )因此,数组常量的一般格式如下:
‘{ val1 delim val2 delim … }’
实例:
‘{1,2,3,4,5}’

psycopg2会将array 作为一个字符串返回,而我希望它返回一个list

import psycopg2

query = """
    select array(select * from (values (1), (2)) s);
"""

conn = psycopg2.connect('dbname=cpn user=cpn')
cursor = conn.cursor()
cursor.execute(query)
rs = cursor.fetchall()

for l in rs:
    print l[0]

cursor.close()
conn.close()

运行结果
[1, 2]

另外一种只取一行,并返回字典

cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
cursor.execute('select Qrcodes FROM SysConfigs WHERE channelid=2')
rs = cursor.fetchone()

print(rs['qrcodes'])

[50000, 60000, 70000, 80000, 90000, 100000]
返回一个tuple

插入数据

a = '16000,26000,36000'
b = '{' + a + '}'

psql = 'UPDATE SysConfigs SET Qrcodes=%s WHERE channelid=1'
cursor.execute(psql, (b,))

javascript获取URL查询参数

var getUrlParameter = function getUrlParameter(sParam) {
    var sPageURL = window.location.search.substring(1),
        sURLVariables = sPageURL.split('&'),
        sParameterName,
        i;

    for (i = 0; i < sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
        }
    }
};

另外一种写法

function getUrlParameter(name) {
    name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
    var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
    var results = regex.exec(location.search);
    return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};

第三种写法

$.urlParam = function(name){
    var results = new RegExp('[\?&]' + name + '=([^]*)').exec(window.location.href);
    if (results==null){
       return null;
    }
    else{
       return results[1] || 0;
    }
}

Python Dictionary Comprehension

从配置表读出配置,第1列为配置名,第2列为配置内容
有多个配置

x = {}
for item in items:
     x[item['cfgname']] = item['cfgvalue']

import json
json.dumps(x)

改成dict comprehension

x = {item['cfgname']:item['cfgvalue'] for item in items}

acme泛域名证书

安装

git clone https://github.com/Neilpang/acme.sh.git
cd acme.sh
./acme.sh --install


[Thu 24 Jan 2019 10:55:02 PM CST] It is recommended to install socat first.                                                                                                  
[Thu 24 Jan 2019 10:55:02 PM CST] We use socat for standalone server if you use standalone mode.                                                                             
[Thu 24 Jan 2019 10:55:02 PM CST] If you don't use standalone mode, just ignore this warning.                                                                                
[Thu 24 Jan 2019 10:55:02 PM CST] Installing to /home/zhiwei/.acme.sh                                                                                                           
[Thu 24 Jan 2019 10:55:02 PM CST] Installed to /home/zhiwei/.acme.sh/acme.sh                                                                                                    
[Thu 24 Jan 2019 10:55:02 PM CST] Installing alias to '/home/zhiwei/.bashrc'                                                                                                    
[Thu 24 Jan 2019 10:55:02 PM CST] OK, Close and reopen your terminal to start using acme.sh                                                                                  
[Thu 24 Jan 2019 10:55:02 PM CST] Installing cron job                                                                                                                        
no crontab for zhiwei                                                                                                                                                           
no crontab for zhiwei                                                                                                                                                           
[Thu 24 Jan 2019 10:55:02 PM CST] Good, bash is found, so change the shebang to use bash as preferred.                                                                       
[Thu 24 Jan 2019 10:55:02 PM CST] OK                                       




.   ~/.acme.sh/acme.sh.env

生成证书

acme.sh  --issue   --dns    -d mydomain.com -d *.mydomain.com

acme.sh 会生成相应的解析记录显示出来, 你只需要在你的域名管理面板中添加这条 txt 记录即可.

等待解析完成之后, 重新生成证书:

acme.sh  --renew --dns   -d mydomain.com  -d *.mydomain.com

用namecheap API

export NAMECHEAP_USERNAME="..."
export NAMECHEAP_API_KEY="..."
export NAMECHEAP_SOURCEIP="..."


acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com

用name.com API

export Namecom_Username="testuser"
export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

acme.sh --issue --dns dns_namecom -d example.com -d *.example.com

....
[Thu 24 Jan 2019 11:09:38 PM CST] Registering account                                                                                                                        
[Thu 24 Jan 2019 11:09:39 PM CST] Registered                                                                                                                                 
[Thu 24 Jan 2019 11:09:40 PM CST] ACCOUNT_THUMBPRINT='KNJKU3gBVaWi_gKre1Ko3rSpZ26gXjk5oBOnkP_PtFc'                                                                           
[Thu 24 Jan 2019 11:09:40 PM CST] Creating domain key
[Thu 24 Jan 2019 11:09:40 PM CST] The domain key is here: /home/zhiwei/.acme.sh/example.com/example.com.key                                                                    
[Thu 24 Jan 2019 11:09:40 PM CST] Multi domain='DNS:example.com,DNS:*.example.com'
[Thu 24 Jan 2019 11:09:40 PM CST] Getting domain auth token for each domain
[Thu 24 Jan 2019 11:09:42 PM CST] Getting webroot for domain='example.com'
[Thu 24 Jan 2019 11:09:42 PM CST] Getting webroot for domain='*.example.com'
[Thu 24 Jan 2019 11:09:42 PM CST] Found domain api file: /home/zhiwei/.acme.sh/dnsapi/dns_namecom.sh  


...
[Thu 24 Jan 2019 11:10:09 PM CST] Found domain api file: /home/zhiwei/.acme.sh/dnsapi/dns_namecom.sh                                                                           
[Thu 24 Jan 2019 11:10:37 PM CST] Successfully logged in.
[Thu 24 Jan 2019 11:10:43 PM CST] Successfully added TXT record, ready for validation.                                                                                      
[Thu 24 Jan 2019 11:10:43 PM CST] Found domain api file: /home/zhiwei/.acme.sh/dnsapi/dns_namecom.sh                                                                           
[Thu 24 Jan 2019 11:10:58 PM CST] Successfully logged in.


[Thu 24 Jan 2019 11:11:23 PM CST] Successfully added TXT record, ready for validation.
[Thu 24 Jan 2019 11:11:23 PM CST] Sleep 120 seconds for the txt records to take effect
...
[Thu 24 Jan 2019 11:13:24 PM CST] Verifying: example.com
[Thu 24 Jan 2019 11:13:27 PM CST] Success
[Thu 24 Jan 2019 11:13:28 PM CST] Verifying: *.example.com
[Thu 24 Jan 2019 11:13:31 PM CST] Success

[Thu 24 Jan 2019 11:13:31 PM CST] Removing DNS records.
[Thu 24 Jan 2019 11:13:49 PM CST] Successfully logged in.


修改android framework关掉app签名检查

https://android.googlesource.com/platform/frameworks/base/+/ccbf84f/services/java/com/android/server/pm/PackageManagerService.java

检查两个包的签名

    public int checkSignatures(String pkg1, String pkg2) {
        synchronized (mPackages) {
            final PackageParser.Package p1 = mPackages.get(pkg1);
            final PackageParser.Package p2 = mPackages.get(pkg2);
            if (p1 == null || p1.mExtras == null
                    || p2 == null || p2.mExtras == null) {
                return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
            }
            return compareSignatures(p1.mSignatures, p2.mSignatures);
        }
    }

如果是我们想豁免的包, 就不检查

   
public int checkUidSignatures(int uid1, int uid2) {
        // Map to base uids.
        uid1 = UserHandle.getAppId(uid1);
        uid2 = UserHandle.getAppId(uid2);
....
        return compareSignatures(s1, s2);
        }
    }

检查签名

    static int compareSignatures(Signature[] s1, Signature[] s2) {
        if (s1 == null) {
            return s2 == null
                    ? PackageManager.SIGNATURE_NEITHER_SIGNED
                    : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
        }
        if (s2 == null) {
            return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
        }
        HashSet set1 = new HashSet();
        for (Signature sig : s1) {
            set1.add(sig);
        }
        HashSet set2 = new HashSet();
        for (Signature sig : s2) {
            set2.add(sig);
        }
        // Make sure s2 contains all signatures in s1.
        if (set1.equals(set2)) {
            return PackageManager.SIGNATURE_MATCH;
        }
        return PackageManager.SIGNATURE_NO_MATCH;
    }

如果需要用Frida进行Hook , 请参考

Magsik模块开发

基础知识

脚本

在Magisk中,你可以在系统启动过程中下面两种模式运行脚本

post-fs-data模式: 阻塞式,启动过程等待执行完成或者执行时间超过10秒.

    好处是在Zygote开启之前就执行

     坏处是:执行有10秒的时间限制,会阻塞启动过程

late_start 服务模式:

   非阻塞式, 启动过程中,脚本并行运行

    好处: 没有时间限制,不会阻塞启动过程

    坏处: 脚本不像post-fs-data模式那样执行得早

脚本又分为两种类型

通用类型: 

   放在 $SECUre_DIR/post-fs-data.d 目录或者 $SECURE_DIR/service.d

脚本文件必须加上可执行权限( chmod +x)

放在 post-fs-data.d 目录下的脚本以 post-fs-data模式运行

   放在 seervice.d 目录下的脚本 以 late_start 模式运行

    将Magisk设置为 Core-Only模式时, 这些脚本也会执行

模块脚本:

    放在模块自己的目录

     只有模块启用时,才会执行

    post-fs-data.sh 运行在 post-fs-data模式

    service.sh 运行在 late_start 服务模式

    Magisk设置为Core-Only模式时, 这些脚本不会执行

注意: 所有的post-fs-data脚本和Magic Mount共享那10秒钟, 

  如果脚本脚本耗时过多, 可能会影响Magic Mount的效果

Frida gadget config

Frida gadget 试图载入一个同名的config文件

https://github.com/frida/frida-core/pull/156

https://github.com/frida/frida-core/blob/master/lib/gadget/gadget.vala

https://www.frida.re/docs/gadget/

简而言之,可执行文件格式包含了链接在可执行文件上的库。我们可以使用lddreadelf(Unix)列出这些库,或者是使用elf_reader.py

载入器会遍历这些库,并把它们映射到进程到的内存空间中去,并在加载之后调用它的构造方法。

添加frida-agent.so作为APK的native库的依赖。

import lief
 
libnative = lief.parse("libandroid.so")
libnative.add_library("libgadget.so") # Injection!
libnative.write("libgadget.so")
配置Frida Gadget

根据文档我们可以知道,Frida Gadgets可以使用配置文件作为参数来进行交互。

  • Listing:交互和frida-server一样
  • Script:使用配置文件中指定的JS脚本进行交互
  • ScriptDirectory:和Script一样,但可以指定多个应用和多个脚本
    Listing交互方式需要android.permission.INTERNET权限。我们可以通过修改manifest文件添加这个权限。不过,如果我们使用的是Script这种交互方式就不需要这一权限。

你能跟Gadget 取任意的文件名,因为有些app会检测自己加载的库里是否有frida字样

config是一个json文件:

interaction   描述交互方式, 默认值是 Listen

teardown 当library卸载时,是minmal还是full. 默认是minimal, 退出时不释放内部线程和内存,以及OS资源

runtime  值可谓 jit 或者 interpreter(默认)

code_signing 仅在iOS平台有意义

Listen模式,如同frida-server那样,gadget监听在localhost:27042

Scripting

{
  "interaction": {
    "type": "script",
    "path": "/home/oleavr/explore.js"
  }
}

参考文章:

https://lief.quarkslab.com/doc/latest/tutorials/09_frida_lief.html

译文:

https://bbs.pediy.com/thread-229970.htm

编译PixelExperience

https://github.com/PixelExperience-Devices/kernel_xiaomi_whyred
https://github.com/PixelExperience-Devices/device_xiaomi_whyred
https://github.com/PixelExperience-Devices/vendor_xiaomi_whyred

下载

repo init -u https://github.com/PixelExperience/manifest -b pie
repo sync -c -j$(nproc --all) --force-sync --no-clone-bundle --no-tags

编译

. build/envsetup.sh
lunch aosp_whyred-userdebug
mka bacon -j$(nproc --all)

设备

Dependency already present in manifest: vendor_xiaomi => vendor/xiaomi
Dependency already present in manifest: kernel_xiaomi_whyred => kernel/xiaomi/whyred
Dependency already present in manifest: LineageOS/android_packages_resources_devicesettings => packages/resources/devicesettings
Dependency already present in manifest: vendor_MiuiCamera => vendor/MiuiCamera

vendor/xiaomi/whyred 来自  https://github.com/PixelExperience-Devices/vendor_xiaomi_whyred

kernel/xiaomi/whyred 来自  https://github.com/PixelExperience-Devices/kernel_xiaomi_whyred

device/xiaomi/whyred 来自  https://github.com/PixelExperience-Devices/device_xiaomi_whyred

编译xposed

准备开发环境
aosp环境
参考 定制Android

perl环境
libconfig-inifiles-perl  (Config::IniFiles)
libfile-readbackwards-perl (File::ReadBackwards)
libfile-tail-perl     (File::Tail)
libarchive-zip-perl (Archive::Zip)